Verständniss frage zu Zeigern
-
mgaeckler schrieb:
[...]Das sind Implementierungsdetails, die den Compilerbauer interessieren. Für den C++-Programmierer ist es Jacke wie Hose. Deswegen schrieb ich ja auch "semantisch".[...]
Eben nicht. Übergabe per Wert bzw. als Referenz interessiert mich als Entwickler, weil es einige große Unterschiede gibt.
Referenzen kann man z.B. nicht auf Referenzen zeigen lassen. Auf Zeiger hingegen schon. Zeiger dürfen auf NULL bzw. auf ungültige Werte Zeigen. Referenzen hingegen nicht. Einen Zeiger kann ich beliebig auf irgendetwas zeigen lassen, weil es eine normale Variable eines Zeigertyps ist. Auf Referenzen trifft das nicht zu.
Deine Aussagemgaeckler schrieb:
func1 und func2 bekommen beide die Adresse von value.
ist falsch.
-
Natürlich gehört der * zum Typ. Aber [] bei Arrays gehört auch zum Typ. Überhaupt gehört in einer Deklaration alles außer dem deklarierten Namen zum Typ:
void (*f)(int(&)[10]); //<-----> <-----------> // Typ ^ auch Typ // | // Bezeichner
-
Tachyon schrieb:
Eben nicht. Übergabe per Wert bzw. als Referenz interessiert mich als Entwickler, weil es einige große Unterschiede gibt.
Referenzen kann man z.B. nicht auf Referenzen zeigen lassen. Auf Zeiger hingegen schon. Zeiger dürfen auf NULL bzw. auf ungültige Werte Zeigen. Referenzen hingegen nicht. Einen Zeiger kann ich beliebig auf irgendetwas zeigen lassen, weil es eine normale Variable eines Zeigertyps ist. Auf Referenzen trifft das nicht zu.Natürlich gibt es auch Unterschiede zwischen Referenzen und Zeigern. Referenzen wurden schließlich nicht nur aus Spass erfunden. Das kommt aber daher, weil Zeiger syntaktisch anders verwendet werden und man/frau mit Zeigern mehr Unfug treiben kann.
Man kann aber auch mit Referenzen Unfug treiben:
#include <string.h> static void destroyer( void ) { int array[255]; memset( array, 0, sizeof( int ) * 255 ); printf( "", array ); } static int &func( void ) { int var = 5; int &ref = var; ref = 6; return ref; } int _tmain(int argc, _TCHAR* argv[]) { int &var = func(); destroyer(); printf( "%d", var ); return 0; }Tachyon schrieb:
Deine Aussage
mgaeckler schrieb:
func1 und func2 bekommen beide die Adresse von value.
ist falsch.
Eine Referenz ist letztendlich nichts anders als eine Adresse wie auch immer der Compilerbauer das realisiert hat.
mfg Martin
-
mgaeckler schrieb:
[...]
Eine Referenz ist letztendlich nichts anders als eine Adresse wie auch immer der Compilerbauer das realisiert hat.mfg Martin
Wie kommst Du nur auf so was?
-
mgaeckler schrieb:
Man kann aber auch mit Referenzen Unfug treiben:
Man kann mit mit so ziemlich allem undefiniertes Verhalten hervorrufen, so wie du es hier zeigst.
-
Tachyon schrieb:
mgaeckler schrieb:
[...]
Eine Referenz ist letztendlich nichts anders als eine Adresse wie auch immer der Compilerbauer das realisiert hat.mfg Martin
Wie kommst Du nur auf so was?
Mehr als 30 Jahre Erfahrung. Selber schon bei einem Compilerbauer gearbeitet.
-
mgaeckler schrieb:
Mehr als 30 Jahre Erfahrung. Selber schon bei einem Compilerbauer gearbeitet.
Sorry, dass ich das so sagen muss, aber dann bist Du offensichtlich nicht sehr tief in die Materie eingestiegen.
-
Tachyon schrieb:
mgaeckler schrieb:
Mehr als 30 Jahre Erfahrung. Selber schon bei einem Compilerbauer gearbeitet.
Sorry, dass ich das so sagen muss, aber dann bist Du offensichtlich nicht sehr tief in die Materie eingestiegen.
Aber er hat recht.
Die ofizielle Sichtweise, daß eine Referenz nur ein andere Name ist, halte ich für die flache Sicht.Die Sichtweise, daß eine Referenz ein verkappter Zeiger ist, halte ich für viel tragfähiger. Da muß man zwar die beiden EInträge der Symboltabelle auf das selbe Ding bei int i=5; int& j=i; als offensichtliche Optimierung erklären, aber hat sofort keine Schmerzen mehr bei sizeof, alignof und Strukturen mit Referenzen oder Referenzen als Übergabeparameter.
-
volkard schrieb:
[...]Die ofizielle Sichtweise, daß eine Referenz nur ein andere Name ist, halte ich für die flache Sicht[...]
Es ist aber die richtige Sicht. Ich könnte jetzt mehrere Beispiele, hauptsächlich in Verbindung mit Inlining und Templates ausführen, wo Referenzen
keineAdressmechanik im Hintergrund benutzen. Bei CPUs mit GPRs gibt es ebenfalls Fälle wo keine Zeiger werkeln.
Und ja, das wird in der Realität eingesetzt.
Es gibt natürlich auch viele Fälle, wo Referenzen über Zeigermechanik umgesetzt werden (geht dort auch nicht anders), aber daraus zu schließen, dass es deshalb immer so sein muss, ist ein Trugschluss .
-
volkard schrieb:
Tachyon schrieb:
mgaeckler schrieb:
Mehr als 30 Jahre Erfahrung. Selber schon bei einem Compilerbauer gearbeitet.
Sorry, dass ich das so sagen muss, aber dann bist Du offensichtlich nicht sehr tief in die Materie eingestiegen.
Aber er hat recht.
Die ofizielle Sichtweise, daß eine Referenz nur ein andere Name ist, halte ich für die flache Sicht.Die Sichtweise, daß eine Referenz ein verkappter Zeiger ist, halte ich für viel tragfähiger. Da muß man zwar die beiden EInträge der Symboltabelle auf das selbe Ding bei int i=5; int& j=i; als offensichtliche Optimierung erklären, aber hat sofort keine Schmerzen mehr bei sizeof, alignof und Strukturen mit Referenzen oder Referenzen als Übergabeparameter.
Allerdings geht es in dem Forum im die Sprache C++ und deren Anwendung in Programmen und gerade nicht primär um Details von Compilerimplementationen. Eine Interpretation, die für das eine nützlich ist, muss nicht unbedingt beim anderen sinnvoll sein (und umgekehrt).
Referenzen als verkappte Zeiger zu betrachten, hilft gerade nicht zu entscheiden, wann welches Sprachmittel zweckmäßig einzusetzen ist.
-
camper schrieb:
[...]
Das ist natürlich noch eine viel bessere Begründung als das, was hinter den Kulissen abläuft.

-
camper schrieb:
Referenzen als verkappte Zeiger zu betrachten, hilft gerade nicht zu entscheiden, wann welches Sprachmittel zweckmäßig einzusetzen ist.
Die andere Sichtweise hilft exakt genauso wenig.

Was hilft, ist die Überlegung, bei welchem Einsatz man Zeit fürs Debuggen spart.
-
Tachyon schrieb:
Es ist aber die richtige Sicht. Ich könnte jetzt mehrere Beispiele, hauptsächlich in Verbindung mit Inlining und Templates ausführen, wo Referenzen
keineAdressmechanik im Hintergrund benutzen. Bei CPUs mit GPRs gibt es ebenfalls Fälle wo keine Zeiger werkeln.
Und ja, das wird in der Realität eingesetzt.
Es gibt natürlich auch viele Fälle, wo Referenzen über Zeigermechanik umgesetzt werden (geht dort auch nicht anders), aber daraus zu schließen, dass es deshalb immer so sein muss, ist ein Trugschluss.Aber die zeigerlosen Fälle sind doch genauso als einfache Optimierung erklärbar.
-
Tachyon schrieb:
Es ist aber die richtige Sicht. Ich könnte jetzt mehrere Beispiele, hauptsächlich in Verbindung mit Inlining und Templates ausführen, wo Referenzen
keineAdressmechanik im Hintergrund benutzen. Bei CPUs mit GPRs gibt es ebenfalls Fälle wo keine Zeiger werkeln.
Und ja, das wird in der Realität eingesetzt.
Es gibt natürlich auch viele Fälle, wo Referenzen über Zeigermechanik umgesetzt werden (geht dort auch nicht anders), aber daraus zu schließen, dass es deshalb immer so sein muss, ist ein Trugschluss .Die Ausdrucksweise "wo keine Zeiger werkeln" zeigt, dass du die beiden Konzepte auf unterschiedlichen Ebenen betrachtest, Referenzen semantisch auf hoher Ebene, Zeiger auf niedriger. Was genau vergleichst du da eigentlich?
Es steht nirgendwo geschrieben, dass Zeiger mit "Adressmechanik" arbeiten müssen. Es bleibt einem in vielen Fällen nichts anderes übrig, aber wenn man sich auf die Verwendung der Mittel beschränkt, die auch mit Referenzen möglich sind, sollte der Compiler den gleichen Code erzeugen.
-
Bashar schrieb:
Die Ausdrucksweise "wo keine Zeiger werkeln" zeigt, dass du die beiden Konzepte auf unterschiedlichen Ebenen betrachtest, Referenzen semantisch auf hoher Ebene, Zeiger auf niedriger.
Was genau verleitet Dich zu der Annahme, dass das meine Sichtweise ist?
-
Bashar schrieb:
Die Ausdrucksweise "wo keine Zeiger werkeln" zeigt, dass du die beiden Konzepte auf unterschiedlichen Ebenen betrachtest, Referenzen semantisch auf hoher Ebene, Zeiger auf niedriger. Was genau vergleichst du da eigentlich?
Es steht nirgendwo geschrieben, dass Zeiger mit "Adressmechanik" arbeiten müssen. Es bleibt einem in vielen Fällen nichts anderes übrig, aber wenn man sich auf die Verwendung der Mittel beschränkt, die auch mit Referenzen möglich sind, sollte der Compiler den gleichen Code erzeugen.Amen.
Optimierungen, die der Compiler bei Referenzen anwenden kann, gelten i.d.R. auch für Zeiger.Es ist für einen Anfänger wichtig, zu verstehen, dass Referenzen nicht viel mehr als Zeiger mit anderer Syntax sind. Wenn das begriffen worden ist, dann kann man souverän urteilen, ob Referenzen oder Zeiger in einem bestimmten Fall angebrachter sind.
Es gibt erschreckend viele fortgeschrittene C++-Programmierer, die zwar mit Referenzen umgehen können, aber diese für sie intern immer noch eine recht mysteriöse Angelegenheit sind. Das trübt teilweise das Urteilsvermögen, denn recht weit verbreitet ist die Ansicht, dass Referenzen langsamer als Zeiger seien, da sie komplexer sind (manchmal hört man es auch umgekehrt). Anfänger glauben manchmal noch, dass eine Referenz ein lokales Objekt am Leben erhalten kann. Aber Referenzen sind eben weder komplexer noch intelligenter als Zeiger.Da es immer wieder Leute gibt, die behaupten, Zeiger seien etwas völlig anderes als Referenzen, nur weil im Standard nicht explizit steht, dass Referenzen durch Zeiger implementiert werden müssen, hilft das auch nicht gerade dem allgemeinen Verständnis.
Es ist nun mal so, dass sich eine Referenz in fast allen Fällen wie ein selbst-dereferenzierender Zeiger verhält - und das Verhalten dürfte im Standard sehr wohl vorgeschrieben sein - nur dass eine andere Wortwahl verwendet wird.
-
Tachyon schrieb:
mgaeckler schrieb:
Mehr als 30 Jahre Erfahrung. Selber schon bei einem Compilerbauer gearbeitet.
Sorry, dass ich das so sagen muss, aber dann bist Du offensichtlich nicht sehr tief in die Materie eingestiegen.
OK. Dann kläre mich mal auf. Zeige mir eine Implementierung mit Referenzen, die man nicht genauso gut auch mit Zeigern machen kann.
Ich behaupte nach wie vor: Referenzen sind nichts anderes als kastrierte Zeiger. Zeig mir ein Beispiel, das das Gegenteil beweist, und Du hast mich überzeugt.mfg Martin
P.S.: Und wenn Du mir nicht glaubst, vieleicht glaubst Du Stroustrup:
"Reference conversions behave much like pointer conversion" (M. A. Ellis, B. Stroustrup, The Annotated C++ Reference Manual, Addison Wesley, 1990, S. 38)
-
Bjarne Stroupstrup Die C++ Programmiersprache S.106 schrieb:
Die naheliegend Implementierung einer Referenz ist die als (konstanter) Zeiger, der bei jeder Benutzung derefenziert wird. Es richtig keine großen Schaden an, sich Referenzen so vorzustellen, solange man daran denkt, daß eine Referenz kein Objekt ist, das manipuliert werden kann wie ein Zeiger:
<Bild>
In einigen Fällen kann ein Compiler eine Referenz wegoptimieren, so daß zur Laufzeit kein Objekt gibt, dass die Referenz repräsentiertWer mal ein großeres Compilerbau-Buch in der Hand hatte, wird auch gelesen, dass es in Programmiersprachen gewollte redundanten Ausdrücke/Befehle gibst, die der Compiler in den meisten regeln auch wegoptimieren könnte, daher würde ich sorgar sagen, dass der zweite Fall sorgar ein Regelfall ist.
-
Athar schrieb:
Es ist für einen Anfänger wichtig, zu verstehen, dass Referenzen nicht viel mehr als Zeiger mit anderer Syntax sind. Wenn das begriffen worden ist, dann kann man souverän urteilen, ob Referenzen oder Zeiger in einem bestimmten Fall angebrachter sind.
Nein, für einen Anfänger ist es wichtig zu wissen, dass eine Referenz ein Aliasname für ein Objekt ist, während ein Zeiger eine Variable ist, die eine Adresse speichern kann. Wie eine Referenz intern umgesetzt ist, braucht den Anfänger dabei nicht zu interessieren.
Für den Compilerbauer ist es hingegen hilfreich zu wissen, dass eine Referenz einen Kontrakt darstellt, der an viel engere Rahmenbedingungen geknüpft ist, als ein Zeiger. Deshalb ermöglichen Referenzen in vielen Fällen Optimierungen, die so mit Zeigern nicht möglich wären.
Die Betrachtungsweise "Referenz == verkappter Zeiger" führt übrigens auch zu so tollen Aussagen wie: "Ich benutze lieber Zeiger, weil man da gleich sieht, dass das eine Referenz übergeben wird, und es eh keine Unterschiede gibt." Was für ein Schwachfug.
-
Tachyon schrieb:
Für den Compilerbauer ist es hingegen hilfreich zu wissen, dass eine Referenz einen Kontrakt darstellt, der an viel engere Rahmenbedingungen geknüpft ist, als ein Zeiger. Deshalb ermöglichen Referenzen in vielen Fällen Optimierungen, die so mit Zeigern nicht möglich wären.
Sorry, das ist nicht korrekt. Diese Optimierungen kann der Compiler nur dann machen, wenn er in dem jeweiligen Kontext sowohl die Referenz als auch das referenzierte Objekt kennt. Wenn er nur die Referenz kennt, sind die Optimierungen nicht mehr möglich. Bei Zeigern ist die Optimierung genauso möglich, wenn der Compiler sowohl den Zeiger als auch das Objekt kennt, auf das der Zeiger verweist.
Zeige mir ein Beispiel, wo es nicht so ist.
mfg Martin