Zeiger und Referenzen
-
Hallo, ich bin mit meinem Buch zum erlerenen von C++ jetzt mit dem Thema "Zeiger und Referenzen" beinahe durch. Hab auch einige Übungsaufgaben gemacht und diese auch meistens korrekt,aber irgendwie weiss ich nicht ob ich dieses Thema so richtig verstanden habe. Alle Aufgaben hätte man auch ohne Zeiger oder Referenzen einfacher lösen können. Klar ist mir das ein Programm mit Zeigern weniger Speicherplatz benötigt. Ist dies wirklich der hauptsächliche Grund warum man sie verwendet oder gibts da noch Andere wichtige. Könnt ihr mir bitte an ganz einfachen Beispielen einige Gründe zum Verwenden von Zeigern geben.
-
Stichworte:
- Binärbaum
- Linked list
- Polymorphie
-
Darf ich fragen, welches Buch? Eigentlich sind Referenzen ungeheuer praktisch, wenn das nicht richtig rüber kam, ist das Buch vielleicht nicht so gut. Zeiger sind durch Referenzen quasi obsolet, bis auf ein paar Anwendungsgebiete die an dieser Stelle in deinem Buch vermutlich noch nicht drangekommen sind (z.B. Polymorphie). Mit Speicherplatzbedarf hat das alles aber eigentlich gar nichts zu tun, das klingt nach Quatsch.
Referenzen benutzt man normalerweise, wenn Funktionen die Werte die ihnen Übergeben wurden verändern sollen. Normalerweise gibt man Funktionsergebnisse man zwar über den Rückgabewert zurück, aber manchmal ist dies unpraktisch, zum Beispiel wenn man mehrere Rückgabewerte hat:
void swap(int& i, int& j) { int tmp = i; i = j; j = tmp; }Weiterhin gibt es auch die Möglichkeit, Referenzen als Rückgabewert zu benutzen. Dann kann man nämlich hinterher dem Funktionsergebnis etwas zuweisen. Normalerweise macht man dies bei Zugriffsoperatoren von Klassen die irgendwelche Daten halten um Zugriff auf diese Daten zu gestatten. Ein einfaches Beispiel kann ich jetzt leider nicht dafür geben, aber denk dir mal wie der Operator[] von Klassen wie std::vector wohl implementiert ist. Die geben nämlich eine Referenz auf das gewünschte Objekt zurück, damit man schreiben kann
, anstatt etwas wiemy_vector.set(x,y);Und dann gibt es auch manchmal noch das Problem, dass man sehr große Objekte an eine Funktion übergeben möchte, dann möchte man sich das fällige Kopieren sparen. In diesem Fall übergibt man das Objekt dann auch per Referenz. Fall man nicht will, dass das Objekt verändert werden darf, per const Referenz.
void foo(big_object const & bar) { // bar benutzen, bar wurde nicht kopiert, ist aber trotzdem nicht veränderbar. }
-
Es ist das Buch, "Lernen und professionell anwenden" von Ulla Prinz. Ein gutes Buch.
Und zu deiner Aussage "Referenzen benutzt man normalerweise, wenn Funktionen die Werte die ihnen Übergeben wurden verändern sollen", steht natürlich auch fast genauso drin.
Und die anderen Beispiele die du mir genannt hast, werd ich im weiteren bestimmt auch noch erkennen.Danke für die Informationen!!
-
stinker06 schrieb:
Es ist das Buch, "Lernen und professionell anwenden" von Ulla Prinz. Ein gutes Buch.
Und zu deiner Aussage "Referenzen benutzt man normalerweise, wenn Funktionen die Werte die ihnen Übergeben wurden verändern sollen", steht natürlich auch fast genauso drin.
Und die anderen Beispiele die du mir genannt hast, werd ich im weiteren bestimmt auch noch erkennen.Danke für die Informationen!!
So gut kann das Buch nicht sein, wenn es nicht in der Lage ist, den simpelsten Anwendungsfall für Zeiger zu zeigen:
Aufgabe: schreibe ein Programm, das eine Datei zeilenweise einliest, die Zeilen sortiert und dann wieder ausgibt.
Wann immer Du Speicher brauchst und Du weißt zum Übersetzungszeitpunkt nicht, wieviel, mußt Du diesen dynamisch anfordern und Du bekommst einen Zeiger darauf zurück.
mfg Martin
-
mgaeckler schrieb:
So gut kann das Buch nicht sein, wenn es nicht in der Lage ist, den simpelsten Anwendungsfall für Zeiger zu zeigen:
Aufgabe: schreibe ein Programm, das eine Datei zeilenweise einliest, die Zeilen sortiert und dann wieder ausgibt.
Wann immer Du Speicher brauchst und Du weißt zum Übersetzungszeitpunkt nicht, wieviel, mußt Du diesen dynamisch anfordern und Du bekommst einen Zeiger darauf zurück.
Du denkst C, nicht C++.
-
mgaeckler schrieb:
So gut kann das Buch nicht sein, wenn es nicht in der Lage ist, den simpelsten Anwendungsfall für Zeiger zu zeigen:
Aufgabe: schreibe ein Programm, das eine Datei zeilenweise einliest, die Zeilen sortiert und dann wieder ausgibt.
Wann immer Du Speicher brauchst und Du weißt zum Übersetzungszeitpunkt nicht, wieviel, mußt Du diesen dynamisch anfordern und Du bekommst einen Zeiger darauf zurück.
mfg Martin
Das kann man ganz ohne Zeiger lösen, indem man std::vector benutzt, std::sort drauf loslässt und den vektor dann wieder ausgibt.
Ein sinnvoller Einsatz für Zeiger ist z.B. die Bereitstellung eines (komplexen) optionalen Parameters in einem Funktionsaufruf.
-
mgaeckler schrieb:
gut in reinem C++ kann man/frau häufig auch auf Zeiger verzichten bzw. diese dann intern von einer Library verwenden lassen. Das kann dann aber unnötiger overkill sein.
Diese Library wäre dann die Standardbibliothek und es ist ganz bestimmt kein Overkill die Standardsprachmittel zu benutzen. In C schreibst du ja auch nicht Assembler, bloß weil es geht.
-
mgaeckler schrieb:
gut in reinem C++ kann man/frau häufig auch auf Zeiger verzichten bzw. diese dann intern von einer Library verwenden lassen. Das kann dann aber unnötiger overkill sein.
RAII ist ein etabliertes Konzept in C++. Davon abweichender Mehraufwand wie manuelle Speicherverwaltung muss seine Rechtfertigung haben.
-
mgaeckler schrieb:
Das hängt meines Erachtens ganz vom Anwendungsfall ab. Die C++ Standardbibliothek hat einen höheren Abstraktionsgrad wie die von C. Das ist immer mit einem höheren Overhead verbunden. Den will man manchmal einfach nicht.
Falsch.
C versus C++ bitte nicht hier. Kannst die passenden Threads im C-Forum erweitern. Derzeit ist da sogar ein recht großer.
-
SeppJ schrieb:
Zeiger sind durch Referenzen quasi obsolet, ...
Bitte was?
Ich glaub da hat jemand SeppJs-Account gehackt...
Sowas kommt doch sicherlich nicht von einem Moderator...Ich verändere auch mal gerne Verweise auf Daten, was
ja (ohne Hacks) mit Referenzen nicht möglich ist.Außerdem kann man Referenzen nicht in (STL-)Containern speichern
und du gehörst ja wohl nicht zu den Leuten, die universell Smart-Pointer verwenden,
oder?Außerdem möchte man manchmal auch einfach 0 zurückliefern oder übergeben...
Gruß,
XSpilleEDIT: Ich gebe dir jedoch Recht, dass man für Übergabe-Parameter und Rückgabe-
Parameter (wesentlich) häufiger Referenzen verwendet.
-
Irgendwie scheinst du einen völlig anderen Programmierstil als ich zu haben, ich habe jedenfalls nie die Notwendigkeit dafür. Warum sollte ich einen Verweis umhängen wollen? Verlasse den Scope der Referenz und mach eine neue. Warum sollte ich 0 zurückgeben wollen, außer bei extrem low-level Sachen? Warum wollte ich Pointer/Referenzen in Container speichern (außer Polymorphie)? Speicher konkrete Objekte oder Iteratoren.
-
(außer Polymorphie)?
Das ist doch aber schon nen ziemlich wichtiges Thema ?
Denk bei jedem Projekt was ueber mehr als ne handvoll source dateien hinausgeht und mehr als 1 Entwickler beteiligt ist, ist Polymorphie(Interfaces) nen Zentrales Thema!Also ich verwend scho "viel" Zeiger
Aber meist auch nur in Verbindung mit Interfaces (Protokollklassen) und PIMPL.
bei mir iss ca. jede 4. Klasse ne pure abstract Klasse (Interface).
und ich verwend auch selten new (eigentlich nur bei PIMPL + ObjectFactories).Meine Meinung:
Wenn wer nen C++ Programm schreibt, ohne obige Themen, also ganz ohne new und Zeiger und und und ... Ist zwar auf der einen Seite Ideal, auf der anderen aber kein typischer C++ Anwendungsfall. Meist hat man eben kein "Hello World" Szenario. In so einem Falle sollt man echt ueberlegen ob c++ ueberhaupt die richtige Sprache fuer das problem waer.Ciao ...
-
SeppJ schrieb:
Irgendwie scheinst du einen völlig anderen Programmierstil als ich zu haben, ich habe jedenfalls nie die Notwendigkeit dafür.

SeppJ schrieb:
Warum sollte ich einen Verweis umhängen wollen?
Bei einer einfachen setter-Funktion mit nicht-POD.
SeppJ schrieb:
Verlasse den Scope der Referenz und mach eine neue.
Als Member-Variable kannst du den Scope nur schwer verlassen

SeppJ schrieb:
Warum sollte ich 0 zurückgeben wollen, außer bei extrem low-level Sachen?
Abstrakt ausgedrückt: Bei optionalen Attributen für ein Objekt.
SeppJ schrieb:
Warum wollte ich Pointer/Referenzen in Container speichern (außer Polymorphie)? Speicher konkrete Objekte oder Iteratoren.
Zur Vermeidung unnötiger Kopien (Komplexität der Objekte).
Nicht jeder Objekt-Typ muss einen Copy-Constructor haben.Gruß,
XSpille
-
XSpille schrieb:
SeppJ schrieb:
Warum sollte ich einen Verweis umhängen wollen?
Bei einer einfachen setter-Funktion mit nicht-POD.
Was hat dies bitte mit POD oder nicht POD zu tun?
@SeppJ,
Mich stört an deiner Aussage irgendwie das Wort "obsolet". Das ist in meinen Augen etwas übertrieben. Referenzen übernehmen sicher einen grossen Bereich, wo man in C Zeiger einsetzt, aber alles können sie nicht schlucken und deshalb sind Zeiger nicht obsolet.Grüssli
-
Dravere schrieb:
XSpille schrieb:
SeppJ schrieb:
Warum sollte ich einen Verweis umhängen wollen?
Bei einer einfachen setter-Funktion mit nicht-POD.
Was hat dies bitte mit POD oder nicht POD zu tun?
Ich meinte "Einfach-zu-kopierendes-Objekt"...
Keine tiefen Strukturen...Die Aussage war allerdings irreführend und falsch, gebe ich dir Recht.
-
Wie sieht so ein Setter konkret bei dir aus?
-
SeppJ schrieb:
Warum sollte ich einen Verweis umhängen wollen?
Fällt dir da wirklich nichts ein?

Wenn du zum Beispiel eine Klasse hast, die gewisse Daten nicht selbst besitzt, sondern extern referenziert, ist es oft sehr hilfreich, den Verweis ändern zu können.Ship::SetTarget(Ship& target);SeppJ schrieb:
Verlasse den Scope der Referenz und mach eine neue.
Wie ist das zu verstehen, bzw. wie führt das am Zeiger-Umhängen vorbei? Man kann den Scope meist nicht einfach so verlassen.
SeppJ schrieb:
Warum sollte ich 0 zurückgeben wollen, außer bei extrem low-level Sachen?
Um einen Nicht-Vorhanden/Nicht-Gültig-Status kennzuzeichnen. Zum Beispiel für eine Suchfunktion. Oder für
Ship* Ship::GetTarget() const; // NULL wenn kein Ziel anvisiertSeppJ schrieb:
Warum wollte ich Pointer/Referenzen in Container speichern (außer Polymorphie)?
Observer Pattern ist so ein Anwendungsfall. Es kann auch sein, dass nur Objekte gleichen Typs benachrichtigt werden, dann ist keine Polymorphie nötig.
Ich bin auch der Meinung, du bist zu stark abgeneigt gegenüber Zeigern. Ich würde mich ohne sie ziemlich eingeschränkt fühlen. Smart muss nur sein, was besitzend ist. Referenzen können zu wenig, um den Zeigern in den übrig gebliebenen Fällen das Wasser zu reichen.