Pointer vs. Reference



  • Hallo Jungs,

    mir geht der Unterschied zwischen Pointern und Referenzen nicht so ganz ein.

    Ich weiß, dass eines der beiden eine Kopie ist (Referenzen?) und eines beinhaltet die Adresse (Pointer). Das müsste doch logisch bedeuten:

    Fall 1:
    Meine main() beinhaltet einen Pointer auf einen Integer mit dem Wert 512. Eine beliebige void-Funktion will als Paramter einen Pointer haben und schreibt den Wert des Pointers um auf 1024.
    Folge: der Werte der ursprünglichen Variable (512) wird mit dem Aufruf der Funktion geändert und für das restliche Programm bleibt der Wert der Variable 1024?

    Fall 2:
    Meine main() beinhaltet eine Variable mit dem Wert 512. Eine beliebige void-Funktion will als Parameter eine Referenz haben und gibt der Referenz einen neuen Wert.
    Der Wert der ursprünglichen Variable bleibt aber für das restliche Programm erhalten, da es eben "nur" eine Referenz war?

    Soweit richtig? Verstehe ich was falsch? Die beiden Elemente zu verstehen (und vor allem sinnvoll einzusetzen) erschweren die Sprache ein wenig, aber dennoch interessant.



  • Ich weiß, dass eines der beiden eine Kopie ist (Referenzen?) und eines beinhaltet die Adresse (Pointer).

    Falsch.



  • Referenz und Pointer sind theoretisch das selbe. Also tritt bei deinem Fall 2 das gleiche ein wie bei Fall 1.
    Wenn bei Funktionen ein Parameter eine (const) Referenz ist, dann meistens aus dem Grund, dass eine eventuell teure Kopie des Objekts vermieden wird, da quasi nur die Adresse an die Funktion übergeben wird. Damit aber nicht versehentlich das Objekt geändert werden kann, wird es als const Referenz übergeben.

    Allgemein gilt: Kann ein Parameter NULL sein (meistens im Sinne von "optional"), dann nimmt man einen Pointer, kann er es nicht sein, dann nimmt man eine Referenz.

    greetz KN4CK3R



  • Lokart schrieb:

    Hallo Jungs,

    mir geht der Unterschied zwischen Pointern und Referenzen nicht so ganz ein.

    Der Unterschied ist wie die Sprache damit umgeht.

    Zeiger sind Dinger die sich gänzlich anders verhalten als das Ding worauf sie zeigen.
    Wenn du ptr = ptr2 schreibst wird die Zeiger-Variable ptr verändert (sie zeigt danach auf was anderes). Die Dinge auf die ptr oder ptr2 zeigen bzw. gezeigt haben bleiben aber unangetastet.

    Referenzen sind dagegen "feste" Verweise auf eine andere Variable. Wenn du eine Referenz einmal initialisiert hast kannst du sie nicht mehr "verbiegen" - also nicht erreichen dass sie auf etwas anderes zeigt.
    Trotzdem ist eine Referenz nur ein Verweis und keine Kopie.
    Wenn du ref = ref2 schreibst wird dabei der Wert des Dings gelesen auf das ref2 verweist, und dann in das Ding reingeschrieben auf das ref verweist.
    ref und ref2 zeigen danach aber immer noch auf das worauf sie vorher gezeigt haben.
    Referenzen verhalten sich also im Gegensatz zu Zeigern an den meisten Stellen wie das Ding worauf sie zeigen.

    Nachdem das jetzt geklärt wäre...

    Eine beliebige void-Funktion will als Paramter einen Zeiger haben und schreibt den Wert des Zeigers um auf 1024.

    Das ist falsch bzw. zumindest sehr irreführend formuliert.
    Die Funktion kann entweder den Wert des Zeigers ändern (=die "Adresse", also ändern auf welches Ding er zeigt), oder die Funktion kann den Wert des Dings ändern auf das der Zeiger zeigt.
    Was du meinst ist der zweite Fall. Die Ausdrucksweise "Wert des Pointers ändern" würde aber den ersten bedeuten.

    Dasselbe nochmal hier

    Eine beliebige void-Funktion will als Parameter eine Referenz haben und gibt der Referenz einen neuen Wert.

    Die Funktion kann der Referenz keinen neuen Wert geben. Sie kann eine Zuweisung ala ref = neuerWert machen. Dabei wird aber nicht die Referenz selbst verändert (das geht in C++ nicht), sondern das Ding auf das ref zeigt geändert.

    Vereinfacht gesagt: eine Referenz ist in C++ ein Zeiger wo der Compiler überall automatisch nen "*" vorne dranschreibt.
    Also ref entspricht (*ptr) .



  • Okay, gut, dann habe ich da was falsch verstanden. Aber gut, danke für die Aufklärung.

    Hat man für Referenzen dann spezielle Anwendungen? Bzw. wann weiß ich wann ich eine Referenz verwende und wann einen Pointer?



  • Referenzen werden bevorzugt. Gute Gründe trotzdem einen Pointer zu benutzen:
    - Soll auch 0 sein können
    - Soll auf einen Speicherbereich zeigen (ergo man will ihn inkrementieren)
    - Man will ihm später einen anderen Wert zuweisen können

    Mittelgute Gründe trotzdem einen Pointer zu benutzen:
    - Der -> Operator sieht einfach cooler aus.



  • Wenn ich mir verschiedene Quellcodes von größeren Projekten auf GitHub ansehe, finde ich dort irgendwie mehr Pointer als Referenzen. Kann natürlich subjektiv sein.

    Gibt es einen speziellen Grund warum Referenzen bevorzugt werden? Hat es Speichermanagement-Gründe? Ist es falsch wenn ich sagen würde das man im Allgemeinen Smart-Pointer bevorzugen sollte? Oder werden trotz intelligenter Zeiger immer noch Referenzen bevorzugt?



  • Lokart schrieb:

    Wenn ich mir verschiedene Quellcodes von größeren Projekten auf GitHub ansehe, finde ich dort irgendwie mehr Pointer als Referenzen. Kann natürlich subjektiv sein.

    Die überwiegende Mehrheit des Codes auf der Welt ist halt einfach schlecht, damit muss man sich abfinden.

    Lokart schrieb:

    Gibt es einen speziellen Grund warum Referenzen bevorzugt werden?

    Ja, sie können die oben aufgezählten Dinge nicht und sind daher weniger Fehleranfällig.

    Lokart schrieb:

    Hat es Speichermanagement-Gründe?

    Im Allgemeinen eher nicht.

    Lokart schrieb:

    Ist es falsch wenn ich sagen würde das man im Allgemeinen Smart-Pointer bevorzugen sollte?

    Smart-Pointer und Referenzen sind zwei völlig andere Anwendungsgebiete. Referenzen sind normalerweise nicht besitzend. Eine Referenz da zu benutzen, wo ein Smartpointer hingehört, macht natürlich wenig Sinn.

    Lokart schrieb:

    Oder werden trotz intelligenter Zeiger immer noch Referenzen bevorzugt?

    Siehe oben. 😉



  • Verabschiede Dich am besten einfach von dem Gedanken, dass Referenzen was mit Pointern zu tun haben. Das macht eh nur Ärger und trägt meiner Meinung nach auch nicht gerade zur Steigerung des Verständnisses bei.
    Stelle Dir Referenzen einfach als Alias für ein Objekt vor. Überall da, wo Du ein Alies brauchst, solltest Du dann Referenzen nehmen.
    Wenn Du also ein Objekt namens A hast, und darauf eine Referenz namens B, dann ist B nur ein anderer Name für A. Wenn B ein Pointer wäre, dann kannst Du zwar die Adresse von A darin speichern, aber auch Adressen von anderen Objekten oder einen Nullzeiger. Das ist semantisch also stark unterschiedlich zu Referenzen.



  • @Lokart
    Der überwiegende Grossteil aller Referenzen die ich verwende sind const-ref Parameter.
    Dann kommen Output-Parameter (das selbe ohne const).

    Und alles andere sind dann schon Spezialfälle.



  • Referenz und Pointer sind theoretisch das selbe.

    Verabschiede Dich am besten einfach von dem Gedanken, dass Referenzen was mit Pointern zu tun haben.

    Es wird langsam kompliziert; zwar sind sie theoretisch das Selbe (mit ein paar Ausnahmen), ich sollte aber nicht beachten, dass sie etwas miteinander zu tun haben. Das Pointer-Reference-Paradoxon? 😛

    Okay, ich gehe mal davon aus, dass Referenzen einfach nur Aliases sind. Aber wo brauche ich einen Alias für ein Objekt? Mir würde spontan kein praktisches Beispiel einfallen.

    Und wenn

    Die überwiegende Mehrheit des Codes auf der Welt ist halt einfach schlecht, damit muss man sich abfinden.

    Wenn Referenzen aber weniger fehleranfällig sind als Pointer, warum werden dann bei den Sachen die ich mir angesehen habe eher Pointer als Referenzen benutzt?

    Ich nehme mal ein kleines fiktives Programm als Beispiel: dieses Programm lädt enorm große Datenmengen und speichert ihren Wert in Variablen. Nun gibt es ein paar Funktionen die mit diesen Variablen arbeiten. Es wäre doch sinnlos diesen Funktionen Kopien der Variable zu übergeben, würde doch den Speicher unnötig in die Höhe treiben. Meiner Meinung nach ist es hier dann doch völlig egal, ob ich eine Referenz oder einen Pointer verwende?
    Und was, wenn man weiß das z.B. nach 3 Funktionen die Variablen nicht mehr gebraucht werden? Dann lösche ich den Inhalt an den entsprechenden Adressen doch? Aber wie?



  • Lokart schrieb:

    Es wird langsam kompliziert; zwar sind sie theoretisch das Selbe (mit ein paar Ausnahmen), ich sollte aber nicht beachten, dass sie etwas miteinander zu tun haben. Das Pointer-Reference-Paradoxon? 😛

    Technisch sind sie quasi gleich, semantisch nicht.

    Lokart schrieb:

    Okay, ich gehe mal davon aus, dass Referenzen einfach nur Aliases sind. Aber wo brauche ich einen Alias für ein Objekt? Mir würde spontan kein praktisches Beispiel einfallen.

    Wie wäre es mit: Immer wenn man einen "read only" Parameter übergibt, bei dem nicht kopiert werden soll; oder wenn man einen Parameter aus einer Funktion heraus ändern möchte? Eigentlich müsstest du dir nur die Standardbibliothek angucken, die ist voll von Referenzen.

    Lokart schrieb:

    Und wenn

    Die überwiegende Mehrheit des Codes auf der Welt ist halt einfach schlecht, damit muss man sich abfinden.

    Wenn Referenzen aber weniger fehleranfällig sind als Pointer, warum werden dann bei den Sachen die ich mir angesehen habe eher Pointer als Referenzen benutzt?

    Weil siehe was ich geschrieben habe? 😕

    Lokart schrieb:

    Ich nehme mal ein kleines fiktives Programm als Beispiel: dieses Programm lädt enorm große Datenmengen und speichert ihren Wert in Variablen. Nun gibt es ein paar Funktionen die mit diesen Variablen arbeiten. Es wäre doch sinnlos diesen Funktionen Kopien der Variable zu übergeben, würde doch den Speicher unnötig in die Höhe treiben.

    Wenn die Kopie unnötig ist, dann ist sie unnötig, ja.

    Lokart schrieb:

    Meiner Meinung nach ist es hier dann doch völlig egal, ob ich eine Referenz oder einen Pointer verwende?

    Hier verwendest du sehr wahrscheinlich einen Pointer + Größenangabe (std::size_t), weil:

    cooky451 schrieb:

    - Soll auf einen Speicherbereich zeigen (ergo man will ihn inkrementieren)

    Lokart schrieb:

    Und was, wenn man weiß dass z.B. nach 3 Funktionen die Variablen nicht mehr gebraucht werden? Dann lösche ich den Inhalt an den entsprechenden Adressen doch? Aber wie?

    Hä? Code Beispiel?



  • Lokart schrieb:

    Okay, ich gehe mal davon aus, dass Referenzen einfach nur Aliases sind. Aber wo brauche ich einen Alias für ein Objekt? Mir würde spontan kein praktisches Beispiel einfallen.

    Semantisch ist ein großer Unterschied. Pointer zeigen irgendwo hin. Im Idealfall auf ein Objekt entsprechenden Typs. Ein (int 😉 sollte also auf ein int Zeigen. Ein Nullpointer zeigt nach 0. Bevor Du also mit einem Pointer arbeitest, solltest Du prüfen, ob Du einen Nullpointer erwischt hast. Ein invalider Pointer zeigt irgendwo hin, da kannst Du nix mehr prüfen.

    Eine Referenz muss initialisiert werden, sie darf nicht Null sein. Wenn Du also eine Funktion hast, die eine Referenz erwartet, so musst Du auch ein entsprechendes Objekt angeben. Technisch wird nur der Pointer übergeben, aber auch die Funktion weiß, da sie ja eine Referenz bekommt, dass dieser Pointer gültig sein muss. Du musst also nicht auf Null prüfen, da das Objekt gültig sein muss.

    Das kann man auch aushebeln, es ist also nicht 100%ig sicher, aber dafür muss man schon quasi Gewalt anwenden. Daher rate ich Dir deutlich dazu, Referenzen zu bevorzugen und Pointer nur da einzusetzen, wo "NULL" bzw. "nullptr" ein valides Argument sein sollen.

    Lokart schrieb:

    Wenn Referenzen aber weniger fehleranfällig sind als Pointer, warum werden dann bei den Sachen die ich mir angesehen habe eher Pointer als Referenzen benutzt?

    Weil die viele Entwickler, die C++ programmieren, kein C++ programmieren können.

    Lokart schrieb:

    Meiner Meinung nach ist es hier dann doch völlig egal, ob ich eine Referenz oder einen Pointer verwende?

    Richtig.
    Hier solltest Du Dich entscheiden, was Du mitteilen möchtest. Soll das ein Zeiger auf ein oder viele Objekte sein (PixelColor 😉 oder ein Array (PixelColor []) oder ist das Objekt, dass halt sehr groß ist, aber existieren auch muss (BitMap640x320 &).

    Hier würde ich eher eine (Bitmap &) nehmen, die den Zeiger auf die vielen Farbinformationen managt, dieses Objekt wäre dann wieder deutlich kleiner und problemlos als Referenz zu übergeben, wenn Du z.B. in die Bitmap reinzeichnen möchtest. Referenz deswegen, weil Du ja nicht auf einen NULL- oder invaliden Pointer zeichnen willst, sondern definitiv auf eine existierende Bitmap.

    Lokart schrieb:

    Und was, wenn man weiß das z.B. nach 3 Funktionen die Variablen nicht mehr gebraucht werden? Dann lösche ich den Inhalt an den entsprechenden Adressen doch? Aber wie?

    delete?

    Ich glaube, ich verstehe die Frage nicht...
    Wenn Du Speicher alloziierst und den Block als Pointer an Methoden übergibst, wäre es ratsam, wenn derjenige, der den Speicher alloziiert hat, diesen auch wieder freigibt.

    Dein fiktives Programm müsste genauer spezifiziert sein, um konkrete Lösungen zu beschreiben. ^^



  • #include <iostream>
    
    int f1() {
    	/* unmengen an quellcode, zig milliarden zeilen, unmengen an speicherverbrauch */
    	return 1;
    }
    
    int f2(int &a) {
    	return a * 2;
    }
    
    int f3(int &a) {
    	return a * 3;
    }
    
    int f4() {
    	return 1024;
    }
    
    int main() {
    	// lade die unmengen an daten
    	int a = f1();
    
    	// die erste funktion die a haben will:
    	std::cout << f2(a) << std::endl;
    
    	// die zweite funktion die a haben will
    	std::cout << f3(a) << std::endl;
    
    	// eine vierte funktion, die nicht mit a arbeitet, folglich könnte ich den speicher
    	// der im moment noch von a belegt wird, doch freigeben?
    	std::cout << f4() << std::endl;
    
    	return 0;
    }
    

    Vor Aufruf von f4() weiß ich, dass ich a nicht mehr brauche. Wie gebe ich den Speicher nun frei?



  • Lokart schrieb:

    Vor Aufruf von f4() weiß ich, dass ich a nicht mehr brauche. Wie gebe ich den Speicher nun frei?

    Etwa so?

    #include <iostream>
    
    typedef int UnmengeAnDatan;
    
    UnmengeAnDaten * f1() {
    	/* unmengen an quellcode, zig milliarden zeilen, unmengen an speicherverbrauch */
    	return new UnmengeAnDaten(1);
    }
    
    UnmengeAnDaten f2(UnmengeAnDaten const &a) {
    	return a * 2;
    }
    
    UnmengeAnDaten f3(UnmengeAnDaten const &a) {
    	return a * 3;
    }
    
    int f4() {
    	return 1024;
    }
    
    int main() {
    	// lade die unmengen an daten
    	UnmengeAnDatan * a = f1();  // Pointer
    
    	if( a )
    	{
    	  UnmengeAnDaten const & alias = *a;
    
    	  // die erste funktion die a haben will:
    	  std::cout << f2( alias ) << std::endl;
    
    	  // die zweite funktion die a haben will
    	  std::cout << f3( alias ) << std::endl;
    
    	  delete a;  // bei Arrays delete [] a, vielleicht eine f1_free( a )-Funktion
    	             // die das sicher weiß?
    	}
    
    	// eine vierte funktion, die nicht mit a arbeitet, folglich könnte ich den speicher
    	// der im moment noch von a belegt wird, doch freigeben?
    	std::cout << f4() << std::endl;
    
    	return 0;
    }
    

    Das Alias brauchst Du nicht, Da Du mit if(a) sicherstellst, dass a existiert. Du kannst also auch f2 und f3 mit (*a) füttern.

    const (siehe f2, f3) solltest Du immer dann verwenden, wenn Du die Daten, die referenziert werden nicht verändern möchtest.

    PS: bei f1 bekommst Du ggfs. eine Exception um die Ohren geschmissen... aber das ist ein anderes Thema. if( a ) aus Prinzip, wer weiß, was Du von f1 geliefert bekommst, vielleicht fängt f1 die Exception und liefert NULL?
    Ansonsten mag ich auch new( std::nothrow ), wenn ich auf die Exception gut verzichten kann...



  • @Lokart: Ich glaube, wir reden hier aneinander vorbei. Wenn du zig Milliarden Daten zu verwalten hast, dann stellt sich erst einmal die Frage, was das für Daten sind. Als nächstes stellt sich die Frage, von wem und wie sie zu verwalten sind. Werden diese Fragen richtig beantwortet, brauchst du dir keine Sorgen mehr um deinen Speicherplatz machen.

    An dieser Stelle sollte man auch mal klar stellen, für welchen Zweck new gedacht ist. new benutzt du, wenn du das Objekt über den Scope hinaus am Leben erhalten musst (siehe Xins Beispiel).



  • Okay, langsam leuchtet es mir ein. Erstmal Danke an Alle für die ausführliche Erklärung.

    Da ich gerade bisschen am Programmieren bin noch etwas über Vektoren, die mit dem Thema zwar nichts zu tun hat, aber wenn der Thread schon steht:

    Kann es sein, dass die folgende Art Elemente in einen Vektor einzutragen ein C++11 Feature ist?

    std::vector< int > b{ 1, 2, 3 ,4 };
    

    Irgendwie findet mein MSVC 2010 das nicht so knorke, obwohl die Initialisierung auf diese Art ja eigentlich machbar sein müsste?

    Und:
    Die Handhabung von mehrdimensionalen Vektoren (bzw. Vektoren von Vektoren) ist mir noch nicht so klar.

    std::vector< std::vector< int > > b;
    

    Bedeutet das b ein Vektor von Vektoren mit dem Typ int ist - aber wie kriege ich da jetzt Elemente rein?
    Ich will nämlich einige Dinge für mein aktuelles Teil in einem Vektor speichern - bestehend aus einem Integer und "einem dazugehörigen Integer" (gibts wohl in PHP Arrays mit Keys => Values). Bestenfalls sogar noch unterteilt in Kategorien, womit ich eigentlich bei "einem Vektor von Vektoren von Vektoren" wäre, aber ich scheitere ja schon an der zweiten Dimension.
    Damit man sich das besser vorstellen kann hier eine kleine "Verdeutlichung":

    Person_1 =>
    	Autos =>
    		bmw
    		audi
    	Frauen =>
    		hannah
    		silke
    		christina
    	[...]
    		[...]
    

    Sprich Hauptelement ist "Person_1", zu Person_1 gehört "Autos" und "Frauen". Die Werte von "Autos" und "Frauen" sind eben die oben stehenden Sachen.



  • Lokart schrieb:

    Kann es sein, dass die folgende Art Elemente in einen Vektor einzutragen ein C++11 Feature ist?

    std::vector< int > b{ 1, 2, 3 ,4 };
    

    Irgendwie findet mein MSVC 2010 das nicht so knorke, obwohl die Initialisierung auf diese Art ja eigentlich machbar sein müsste?

    Ja das ist ein C++11 Feature. Selbst in MSVS 2012 haut das noch nicht hin.

    Lokart schrieb:

    Die Handhabung von mehrdimensionalen Vektoren (bzw. Vektoren von Vektoren) ist mir noch nicht so klar.

    std::vector< std::vector< int > > b;
    

    Erstmal: Da du ja offensichtlich schon C++11 nutzt, ist so ein Konstrukt nicht mehr so oft nötig. std::vector<std::vector> bedeutet nämlich, dass du eine Liste von Listen hast. Das ist nicht nötig, da die innere Dimension meist eine bekannte feste Größe hat und demnach nicht dynamisch sein muss. Ergo nicht std::vector<std::vector> sondern std::vector<std::array>

    Lokart schrieb:

    Bedeutet das b ein Vektor von Vektoren mit dem Typ int ist - aber wie kriege ich da jetzt Elemente rein?

    Na, wenn der Container einen Container will, dann musst du ihm einen geben:

    vecor< vector<int> > aussen;
    vector<int> innen = { 1, 2, 3, 4, 5 };
    aussen.push_back( innen );
    cout << endl << aussen[0][0];
    

    Lokart schrieb:

    bestehend aus einem Integer und "einem dazugehörigen Integer" (gibts wohl in PHP Arrays mit Keys => Values). Bestenfalls sogar noch unterteilt in Kategorien, womit ich eigentlich bei "einem Vektor von Vektoren von Vektoren" wäre, aber ich scheitere ja schon an der zweiten Dimension.
    Damit man sich das besser vorstellen kann hier eine kleine "Verdeutlichung":

    Person_1 =>
    	Autos =>
    		bmw
    		audi
    	Frauen =>
    		hannah
    		silke
    		christina
    	[...]
    		[...]
    

    Sprich Hauptelement ist "Person_1", zu Person_1 gehört "Autos" und "Frauen". Die Werte von "Autos" und "Frauen" sind eben die oben stehenden Sachen.

    Aso, das willst du also. Ganz schön viele Frauen hat so eine Person :D. Ich hab da mal ein Versuch gemacht. Herausgekommen ist das:

    #include <iostream>
    #include <map>
    #include <string>
    #include <vector>
    using namespace std;
    
    enum Werte { Autos, Frauen };
    
    int main()
    {
    	map< string, map<Werte,vector<string>> > Personen;
    
    	// Zu Person_1
    	{
    		map<Werte,vector<string>> zu_person_1;
    
    		vector<string> autos;
    		autos.push_back("bmw");
    		autos.push_back("audi");
    		zu_person_1[Autos] = autos;
    
    		vector<string> frauen;
    		frauen.push_back("hannah");
    		frauen.push_back("silke");
    		frauen.push_back("christina");
    		zu_person_1[Frauen] = frauen;
    
    		Personen["Person_1"] = zu_person_1;
    	}
    
    	// Testausgaben
    	{
    		cout << endl << "Autos: ";
    		for(auto& a : Personen["Person_1"][Autos])
    			cout << a << ' ';
    
    		cout << endl << "Frauen: ";
    		for(auto& f : Personen["Person_1"][Frauen])
    			cout << f << ' ';
    	}
    }
    


  • Vielen Dank! 🙂



  • cooky451 schrieb:

    Lokart schrieb:

    Es wird langsam kompliziert; zwar sind sie theoretisch das Selbe (mit ein paar Ausnahmen), ich sollte aber nicht beachten, dass sie etwas miteinander zu tun haben. Das Pointer-Reference-Paradoxon? 😛

    Technisch sind sie quasi gleich, semantisch nicht.

    Technisch können sie gleich sein. Sind sie aber nicht in jedem Fall, und müssen sie auch nicht. Ich würde mich davon verabschieden, dass Refernzen was mit Pointern zu tun haben.

    [quote:55ebf8ce7b="ISO/IEC
    14882/2011 8.3.2§4"]It is unspecified whether or not a reference requires storage
    Das sagt eigentlich deutlich, dass bei Referenzen technisch nicht zwangsläufig mit Zeigern realisiert werden müssen...

    PS: Achso, semantisch ist natürlich der folgende Absatz viel interessanter:
    [quote:55ebf8ce7b="ISO/IEC
    14882/2011 8.3.2§5"]There shall be no references to references, no arrays of references, and no pointers to references. The
    declaration of a reference shall contain an initializer [...] A reference shall be initialized to refer to a valid object
    or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only
    way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer,
    which causes undefined behavior.[...]
    Das zeigt schon sehr deutlich die Unterschiede auf.


Log in to reply