Zeiger: Sinn | Unsinn.
-
Daß es in anderen Sprachen keine Zeiger gebe, ist ein Märchen, wie Marcus schon herausgestellt hat. Auch Java (beispielsweise) hat Zeiger, nennt sie nur anders. Auch in anderen Sprachen kann es manche Zeigerfehler (Nullpointer) geben, wie sie oft als für C++ typisch angesehen werden. Die Sicherheit in Sprachen wie Java kommt nicht durch ihre angebliche Zeigerlosigkeit, sondern durch zwei andere Maßnahmen: Erstens können Objekte nicht explizit freigegeben werden, wodurch das Objekt, auf das ein Zeiger zeigt nie ungültig werden kann (es gibt keine dangling pointer). Zweitens gibt es keine Zeiger-Arithmetik, man kann also den Wert eines Zeigers ausschließlich durch Zuweisung (und nicht etwa durch Addition eines ints) ändern. Durch beide Maßnahmen zusammen wird erreicht, daß ein Zeiger immer auf einen Bereich zeigt, der dem Programm tatsächlich gehört.
Diese Maßnahmen machen Sprachen wie Java tatsächlich sicherer, indem sie wichtige Fehlerquellen ausschließen. Aber sie kosten auch was, und wie ich finde, nicht gerade wenig (z.B. Garbage Collection oder der drastisch eingeschränkte Nutzen von Destruktoren in Java).
Es ist ein wesentlicher Bestandteil der Philosophie von C++, daß die Kosten für alle Programm-Konstrukte ausschließlich durch den Programmierer und nicht durch die Laufzeitumgebung bestimmt werden. Das *kann* selbstverständlich zu gefährlichen Szenarien führen. Außerdem kann man diese Philosophie teilen oder nicht. Aber wenn man in C++ programmiert, dann muß man sie akzeptieren. Ebenso übrigens, wie man bei Sprachen wie Java deren inherente Ineffizienz akzeptieren muß. Und zusätzlich die Tatsache, daß man als Programmierer niemals die vollständig Kontrolle über das Programm hat (Stichwort Garbage Collector).
Schließlich dieses Statement "C++ ist nur was für Profis", das du eigentlich nicht hören wolltest. Es stimmt einfach! Ich würde allerdings weiter gehen. Falls man ein professionelles Programm haben möchte, das den allgemein anerkannten Qualitätsmaßstäben für Sofware genügt, dann braucht man Profis, die es erstellen. (Hiermit meine ich nicht Profis im Sinne von "sie verdienen ihr Geld damit"!) Das gilt für alle Programmiersprachen, nicht bloß für C++. Und bezogen auf die Programmiersprache (die ja nur ein Teil der bei der Sofware-Entwicklung verwendeten Tools ist) bedeutet das, daß der Entwickler sie gefälligst gut zu kennen hat, ihre Stärken genauso, wie ihre Schwächen und potentiellen Fehlerquellen. Punkt. Ein C++-Entwickler muß wissen, wie er mit Zeigern umzugehen hat und auch, welche Möglichkeiten (z.B. Smart Pointer) es gibt, die Gefahren im Zusammenhang mit Zeigern zu verringern.
Fazit: Es ist nicht die Sprache (bzw. deren Möglichkeiten), die gefährlich ist und zu Fehlern führt. Es ist der Programmierer, der vielleicht nicht sorgfältig arbeitet oder seine Sprache nicht ausreichend kennt. Und sorry, dieses Statement, daß Fehler in C++ meistens durch die falsche Verwendung von Zeigern entstehen, weshalb Zeiger verboten/abgeschafft gehören, ist einfach Quatsch. Schaffe die Leute ab, die diese Fehler programmieren, sorge dafür, daß dein Programm von Profis geschrieben wird. Dann kannst du C++, Java oder meinetwegen auch Basic verwenden - und wirst ein gutes Programm erhalten. Ob du's glaubst oder nicht: Wenn meine Programme Fehler enthalten, ist das höchst selten (fast hätte ich geschrieben: nie) auf die falsche Verwendung von Zeigern zurückzuführen. Ich kann nämlich damit umgehen.
Stefan.
-
Hat nicht jede imperative Sprache Zeiger? Manchmal heißen sie Referenzen (Java, Eiffel), manchmal Access Types (Ada), und manchmal eben einfach Zeiger (in Lisp vermeidet man das Wort und sagt einfach Werte, aber weiß im Hinterkopf eigentlich, dass es Zeiger sind).
Zeiger haben 2 grundlegende besondere Eigenschaften: 1) sie definieren den Begriff der Identität eines Objektes (OOP Basics: ein Objekt hat Zustand, Verhalten und Identität) -- wenn 2 Zeiger gleich sind, und nur dann, bezeichnen sie das selbe Objekt. 2) es gibt einen besonderen Wert, den kein Zeiger auf ein Objekt haben kann (Nullpointer, null, Void, NIL ...). Bis hierher geht es einfach nicht ohne Pointer.Es sind doch die zusätzlichen C++-Eigenschaften von Zeigern, die die Schwierigkeiten machen. Pointer-Arithmetik und Pointer-auf-Pointer. Wenn man sich davon weitestgehend fernhält, oder einfach nur ein wenig aufpasst was man tut, kommt man mit Pointern wunderbar aus.
-
Danke für die exzellenten Antworten. Bin positiv überrascht. Freut mich, dass ich tatsächlich begründete Antworten erhalte.
@dreaddy: Ein Listenfeld mit 10.000 Einträgen würde ich als Array nutzen. Gut, ein Array ist letztendlich auch nichts anderes als ein Datenfeld mit einem Zeiger auf Array(0).
@Marc++us:
Da werde ich mir nachher mal meinen Chefprogrammierer anhauen. Stark.
Das wußte ich nicht. Sogar die von mir gelesenen Bücher haben es nie erwähnt.
- Danke für den Hinweis. Ist also auch in OBERON Zeigerarithmetik möglich? (Google ergab interessante Hinweise.)
@virtuell Realisticer: Sicher versuche ich mir Zeiger in C++ anzueignen, letztendlich sind viele bekannte Elemente der Programmierung nichts anderes als Zeiger, aber - zuweilen stutze ich doch und frage mich, ob ich das wirklich brauche. Immerhin habe ich bisher nicht nur Müll und Datenbankprogrammchen programmiert.
Die Absicht von C++ gegenüber PASCAL ist verständlich, aber C++ hat sich in vielen Bereichen von Maschinenprogrammierung wegbewegt und da frage ich mich, ob es sinnvoll ist bestimmte Konstrukte weiterhin zu nutzen. - Selbstverständlich hängt gute Programmierung vom Programmierer ab, sowie vom Compiler. Keine Frage.
@DStefan: Viele Entwickler halten das Fehlen des 'Garbage Collectors' in C++ für eine große Fehlerquelle. Ich persönlich teile hierbei Deine Meinung, da ich mich lieber um solche Dinge selber kümmere.
Natürlich, der Programmierer ist die Fehlerquelle, aber vielfach wird argumentiert, dass eben diese Punkte C++ so unsicher machen. Ich erwarte sehr wohl, dass ein guter C++-Entwickler Pointer sicher einsetzen kann, nur lohnt sich auch der Aufwand wenn es in anderen Sprachen einfacher geht?
Deine Aussage, dass ein Entwickler erst gut ist wenn er die Sprache kennt ist goldrichtig. Dann kann ich Dir zustimmen. Spreche aus eigener Erfahrung. Aber, die Frage war eher die, ob Zeiger nicht C++ unnötig kompliziert machen? Und ob andere Sprachen dahingehend nicht eine besser Lösung haben? Ich gehe nämlich davon aus, dass in C++ Zeiger noch umfangreicher eingesetzt werden können als in PASCAL, OBERON oder sonst wo.
@Bashar: Vielleicht habe ich mich falsch ausgedrückt. (Siehe unten.)
Hinweis: Mit Zeiger-Problem meinte ich keineswegs Referenzen u.ä., ohne könnte ich gar nicht auskommen. Keine Frage. Aber Zeigerarithmetik, Speichermanipulierung und andere 'mögliche' Spielereien (wobei ich die meisten nur von der Idee kenne) fand ich albern. Und dabei fragte ich mich warum solche Problemstellungen wo anders 'anders' gelöst werden. Das musst doch einen Grund haben? C++-Entwickler haben nicht das Patent auf Profi-Entwicklung gepachtet. Nur weil eine Sprache umfangreich und komplexer ist macht sie die Entwickler nicht schneller, besser oder smarter.
Ebenso ist mir klar, dass viele Bereiche der Entwicklung (indirekt od. direkt) Zeiger nutzen, und dass C++ hier noch maschinennaher arbeitet. Aber, brauche ich die maschinennahe Entwicklung für nicht-maschinennahe Entwicklung? PASCAL z.B. finde ich nicht so 'maschinennah' (eigenartiges Wort) und dennoch werden exzellente und schnelle (aufwendige) 3D-Animationen (oder Spiele) mit fabriziert.
Ich bin durchaus so weit C++ begeistert, dass ich dazulernen möchte. Ihr könnt mich ruhig also versuchen zu bekehren. Es ist keineswegs so, dass ich Zeiger vermeide, aber ich betrachte sie vielmehr als Referenzen, und da ich solcherlei bisher anders gelöst habe (vielleicht nicht minder schneller) frage mich sehr wohl wozu ich all die 'Möglichkeiten' brauche.
Frage: Wo nutzt ihr Zeiger? Wo könnt ihr nicht auf sie verzichten (Beispiele)?
(Sollte ich eine Frage ausgelassen haben stellt sie noch mal. Es waren so umfangreiche Postings, dass ich sicherlich etwas übersehen habe.)
-
Vielleicht sollte man bei solchen Diskussionen stets zwischen
(a) MASCHINENNAHER
und
(b) NICHT-MASCHINENNAHER (vielleicht wißt ihr einen bessern Ausdruck)
Programmierung unterscheiden. Wobei a) jene Programmierung zur Steuerung von Maschinen und Maschinenmanipulierung dient, während b) zur grafischen Anwenungen im Stile von Fenstern, Datenbankanwendungen angewendet wird.
Hierbei ergeben sich nämlich unterschiedliche Problemstellungen und Wünsche. Nicht? (Ergänzend: Und Kostenfaktoren sowie Kostenpunkte und Budgeteinteilungen.)
-
rafa schrieb:
Hinweis: Mit Zeiger-Problem meinte ich keineswegs Referenzen u.ä., ohne könnte ich gar nicht auskommen.
OK, aber dafür braucht man eben das Konstrukt "Zeiger", deshalb sag ich das. Auch weil in solchen Diskussionen immer gerne die unterschiedlichen Auffassungen, was eine Referenz ist, unkritisch durcheinandergeworfen werden, was am Ende nur maximale Verwirrung(TM) hinterläßt.
Und dabei fragte ich mich warum solche Problemstellungen wo anders 'anders' gelöst werden.
Die Frage ist IMHO eher, warum es in C++ gerade so gelöst ist -- ältere Sprachen haben interessanterweise keine C-mäßigen Zeiger (Beispiele FORTRAN und LISP). Einer der Väter von C muss es wohl besonders lustig gefunden haben, dass man mit Zeigern so einige verschiedene Konzepte zu einem verallgemeinern kann. Dass das ganze dann in einen Typ mündet, der im Prinzip nicht viel mehr als eine numerische Adresse ist, kam ihnen gerade Recht, denn sie wollten damit ein Betriebssystem schreiben.
Naja, und C++ hat das eben übernommen.
-
Erstens können Objekte nicht explizit freigegeben werden, wodurch das Objekt, auf das ein Zeiger zeigt nie ungültig werden kann (es gibt keine dangling pointer).
foo = null???
Zeiger sind eine Mischung aus zwei Modellen, dem des Moikers und dem des Iterators (auch wenn Iteratoren manchmal auch noch was anders sind).
Und genau aus dieser Mischung entsteht das Problem, da viele mit dem Verhalten als Iterator nicht klar kommen.
-
Helium schrieb:
foo = null???
Das setzt den Zeiger auf Null, aber zerstört nicht notwendigerweise das dahinterliegende Objekt. Das kann ja noch von anderen Zeigern referenziert werden. Wenn du ein Objekt explizit zerstörst, kann es immer noch referenziert werden, denn es können beliebig viele Pointer darauf verweisen.
[ Das betrifft offensichtlich nur eingebaute Sprachmechanismen, über die unterhalten wir uns hier ja, nicht shared_ptr und ähnliches. ]
-
rafa schrieb:
Es ist keineswegs so, dass ich Zeiger vermeide, aber ich betrachte sie vielmehr
als Referenzen, und da ich solcherlei bisher anders gelöst habe (vielleicht
nicht minder schneller) frage mich sehr wohl wozu ich all die 'Möglichkeiten'
brauche.Wohl die meisten Programmierer werden nicht alle Features einer Sprache
einsetzen. Deswegen kann man diese Features aber noch lange nicht aus der
Sprache entfernen, denn diese definieren doch die Sprache.rafa schrieb:
Vielleicht sollte man bei solchen Diskussionen stets zwischen
(a) MASCHINENNAHER
und
(b) NICHT-MASCHINENNAHER (vielleicht wißt ihr einen bessern Ausdruck)
Programmierung unterscheiden. Wobei a) jene Programmierung zur Steuerung von
Maschinen und Maschinenmanipulierung dient, während b) zur grafischen Anwenungen
im Stile von Fenstern, Datenbankanwendungen angewendet wird.Hierbei ergeben sich nämlich unterschiedliche Problemstellungen und Wünsche.
Nicht? (Ergänzend: Und Kostenfaktoren sowie Kostenpunkte und
Budgeteinteilungen.)Das ist voellig korrekt. Aber die Sprache C wurde zur Maschinennahen
Programmierung entwickelt. Das die Sprache auch fuer normale Softwareentwicklung
eingesetzt wird, daran dachte damals niemand. Da sich C++ an C orientiert
(oder darauf aufbaut - wie auch immer), ist es nur selbstverstaendlich, dass
Zeiger weiterhin Bestandteil dieser Sprache sind.Ganz nebenbei, waere sonst ein Standard C _kein_ gueltiges Standard C++
Programm (was natuerlich nicht immer so ist).Wie Bashar schon sagte, passiert, wenn man einwenig aufpasst und sich gedanken
macht, eigentlich sehr wenig beim Einsatz von Zeigern.mfg
v R
-
Das setzt den Zeiger auf Null, aber zerstört nicht notwendigerweise das dahinterliegende Objekt.
Sorry, bin noch nicht ganz wach. Vergesst den Teil meiner Nachrnicht.
-
rafa schrieb:
Ist also auch in OBERON Zeigerarithmetik möglich? (Google ergab interessante Hinweise.)
Oberon als Produkt der Familienlinie Modula2 und Modula3 kennt auch den POINTER TO.
Es ist aber vielleicht falsch, hierzu Zeigerarithmetik zu sagen... solche Dinge wie Zeiger = Zeiger + 3 wie in C und C++ sind nicht so oft erlaubt.
Allgemein muß ich sowieso bei diesen Diskussionen was sagen: ich höre immer wieder als Gegenargument zu C++, daß man wg. den Zeigern aufpassen muß oder wegen Speicherlöchern.
Aber nach meiner bisherigen Erfahrung sind dies in unseren Projekten die seltensten Fehlerquellen. Manchmal sind dangling pointer im Zusammenhang mit der Zerstörung von Threads in der Tat Grund zum Stirnrunzeln gewesen, aber das war eher ärgerlich aber leicht zu finden. Deadlocks sind ebenfalls von Zeit zu Zeit Quelle von Ärgernis.
Am häufigsten kommen so Dinger vor, daß ein Eventhandler mit dem falschen Knopf verlinkt ist oder gar nicht, oder daß irgendwas mal zu früh aufgerufen wird und keiner auf mögliche Exceptions geachtet hat, etc. Fehler wirken sich bei uns eher in "Nichtfunktion" einer Aktion aus. Aber nicht in einem Absturz.
Nur hört man ja oft, daß in C++ sichere Programme ohne Abstürze aus heiterem Himmel gar nicht möglich sind, nur kann ich diese Aussage nicht mit meiner Erfahrung in Deckung bringen.
-
Was hindert den unerfahrenen Programmierer daran Zeiger nur wie Referenzen einzusetzen( es gibt auch `echte' referenzen in C++) ? und wenn selbst dann noch probleme mit dem speicher herrschen gibt es immernoch garbage collectoren fuer c++. aber wieso sollte man zeiger nicht in der sprache haben und damit erfahrenen programmierern die moeglichkeit zur effizienten programmierung nehmen?
-
thomas001 schrieb:
Was hindert den unerfahrenen Programmierer daran Zeiger nur wie Referenzen einzusetzen ... aber wieso sollte man zeiger nicht in der sprache haben und damit erfahrenen programmierern die moeglichkeit zur effizienten programmierung nehmen?
Naja, schöne Idee, aber didaktisch gefährlich, da der typische Mensch leider weder weise noch klug ist.
Dieser Ansatz hat leider den Schönheitsfehler, daß man einem Kind einen riesigen Werkzeugkasten hinstellt, und sagt: "nicht mit den spitzen Sachen spielen, das ist für Erwachsene". Aus dem gleichen Grund gibt's auch Wohnungsbrände.
Jeder Ansatz, der für eine Applikation, ein Tool oder eine Sprache Vernunft, Ruhe und Weisheit vom Benutzer erfordert, wird scheitern.
-
Marc++us schrieb:
Jeder Ansatz, der für eine Applikation, ein Tool oder eine Sprache Vernunft, Ruhe und Weisheit vom Benutzer erfordert, wird scheitern.
Hmmmmm - jetzt weiß ich endlich, warum so viele Software-Projekte (unabhängig von der Programmiersprache) scheitern. Sie alle fordern Vernunft, Ruhe und Weisheit vom Benutzer. Oder etwa nicht?
Stefan.
-
Marc++us schrieb:
Allgemein muß ich sowieso bei diesen Diskussionen was sagen: ich höre immer wieder als Gegenargument zu C++, daß man wg. den Zeigern aufpassen muß oder wegen Speicherlöchern.
Aber nach meiner bisherigen Erfahrung sind dies in unseren Projekten die seltensten Fehlerquellen. Manchmal sind dangling pointer im Zusammenhang mit der Zerstörung von Threads in der Tat Grund zum Stirnrunzeln gewesen, aber das war eher ärgerlich aber leicht zu finden. Deadlocks sind ebenfalls von Zeit zu Zeit Quelle von Ärgernis.
Am häufigsten kommen so Dinger vor, daß ein Eventhandler mit dem falschen Knopf verlinkt ist oder gar nicht, oder daß irgendwas mal zu früh aufgerufen wird und keiner auf mögliche Exceptions geachtet hat, etc. Fehler wirken sich bei uns eher in "Nichtfunktion" einer Aktion aus. Aber nicht in einem Absturz.
Nur hört man ja oft, daß in C++ sichere Programme ohne Abstürze aus heiterem Himmel gar nicht möglich sind, nur kann ich diese Aussage nicht mit meiner Erfahrung in Deckung bringen.
Dem kann ich nur zustimmen!
Und ergänze eine rethorische Frage: Für *wen* sind solche Fehler "eher ärgerlich aber leicht zu finden"? Eben nicht für die, die Pointer(-arithmetik) für des Teufels vorletzten Streich gegen die Christenheit halten. Weil sie sie halt nicht beherrschen.Stefan.
-
Erstmal danke an alle. Das war sehr aufschlußreich.
PASCAL / OBERON: Es ist für wahr: PASCAL kennt den Pointer. Und das ist erschreckend, denn bisher bin ich nicht darauf gestoßen. Eigenartig. Wie auch immer, eine interessante Erweiterung muss ich sagen.
CHEFENTWICKLER: Immerhin mein Mentor, hat sich hierin geirrt. Was ihm sicherlich nicht schmeckt. Besser noch, er leugnt es gesagt zu haben, dass PASCAL keine Zeiger kennt. Zitat: 'Ich sagte, in PASCAL werden Zeiger kaum genutzt.' Da ich allerdings im vollen Besitz meiner geistigen Kräfte bin und nur unwesentlich unter Hör- sowie Gedächtnisproblemen leide
, bin ich überrascht, da er es nun leugnet. Aber, das ist wohl ein anderes Thema. (Vermutlich ist es ihm unangenehm.)
Nun habe ich in mühevoller Arbeit das M&T-Verlag 'C/C++ Kompendium' mit fast 1300 Seiten durchgearbeitet, der nächste 1000-Seiten-Schinken wartet schon. Gut manche Bereiche habe ich überflogen, da Programmiersprachen gewisse Dinge doch gemeinsam haben. Aber ich bin über Zeiger positiv überrascht. Nicht alle Bereiche erscheinen mir zurzeit schlüssig, aber vielleicht braucht es hier noch der praktischen Anwendung. Meine anfängliche Ablehnung und Skepsis habe ich zumindest abgelegt. (Nicht zu unterschätzen der 'A-H-A'-Effekt bei bereits bekannten Methoden, welche sich in C++ als Zeiger entpuppen.)
Dank an alle.
Info: Sollte jemand gute Bücher zu C++ (insb. VC++ und Win32-GUI ohne MFC)kennen, möge er mir bitte schreiben (sicher gibt es hier aber genug Threads zu). Ich bin für hilfreiche Bücher stets dankbar (bitte keine Einsteigerbücher wie 'Schritt für Schritt' oder 'for Dummies' mit hunderten von Seiten über Entwicklungsumgebungsbeschreibungen - tolles Wort).
-
Hm, diese Zeigerdiskusion hab ich in der Firma mit meinem Vorgesetzten auch führen müssen.
Er fand Zeiger sehr gefährlich und sie wurden schlicht weg verboten.
Er schrieb dann sinngemäß eine Funktion
T * foo() { T t; return &t; }
um in
T & foo() { T t; return t; }
und war nun fest davon Überzeugt das dies nun sicher wäre da kein Zeiger verwendet wird.
Die 'Garbage Collector' führten bei uns in der Praxis zu Quellcode der ähnlich wie diesem hier aussah:
public sub foo() myObjekt.test() ' Frage ob ich schon tot bin [..] myObjekt.test() ' Wieder die Frage ob die software lebt [..] myObjekt.test() ' Irgendwie hat die Software ein Problem mit der Zukunft :clown: end sub
Die Kommentare im Quelltext sind zwar aufmunternd, aber nich die Wartungsarbeit die dahintersteht.
-
rafa schrieb:
Es ist für wahr: PASCAL kennt den Pointer. Und das ist erschreckend
Das ist hoffentlich ein Scherz. Ohne Zeiger könntest du in Pascal keine dynamischen, rekursiven Datenstrukturen wie Bäume oder Listen aufbauen.
-
@Bashar: Mein Schwerpunkt lag bisher in Visual Basic 6 / 7 und da gibt es 'standardmäßig' (sieht man mal von WinAPI-Umwegen und ASM-Addon ab) keine Zeiger (dafür Referenzen), dennoch habe ich sehr wohl Bäume, Listen und rekursive Strukturen erstellt. Es geht bis zu einem gewissen Grad auch ohne Referenzen und Zeiger, nur ist es langsamer. - PASCAL und DELPHI nutzte ich in anderen Bereichen, wo Zeiger nicht aufkamen (bzw. ich die Notwendigkeit bisher nicht sah).
Ergänzend: Wie gesagt, vieles (sehr vieles) geht mit und ohne Zeiger.
-
rafa schrieb:
Es geht bis zu einem gewissen Grad auch ohne Referenzen und Zeiger, nur ist es langsamer.
klick & bunti kann jeder ..
effizienz ist das A und O beim programmieren
-
1ntrud0r: Da stimme ich Dir zu. Nur lassen wir mal eine mögliche (sich anbannende) Diskussion über Visual Basic vs. C++.
Ergänzend: Das 'A und O' der Programmierung ist Projektzeit und Effizienz denke ich, daher VB mit C++ (bei uns im Unternehmen).