Call by value, call by reference
-
Sie sind nicht gleichwertig.
Wann sollte man denn by_ref und wann by_ref2 verwenden.
Kommt drauf an, was du machen moechtest.
-
Ist es denn so, dass bei by_ref eine Kopie erstellt wird, die zwar aufs gleiche Objekt zeigt, aber keine Referenz im eigentlichen Sinne ist?
Denn bei by_ref2 arbeitet man ja wirklich mit einer Referenz. Ich gebe hier ja wirklich nur die Speicheradresse weiter und es zeigen keine "zwei Objekte" auf die gleiche Speicheradresse. Sondnern nachwievor nur eins und das gebe ich hier weiter.
-
Was da wie wo genau kopiert wird "entscheidet" der Optimizer. Bei so etwas Einfachem wird wohl eh einfach alles wegoptimiert. (Also alles geinlined.)
Sprachlich erzeugen Pointer- und Referenzvariante erstmal ein Alias für das gleiche Objekt. Nur eben, dass man die Referenz danach nicht mehr ansprechen kann.
-
blub85 schrieb:
Ist es denn so, dass bei by_ref eine Kopie erstellt wird, die zwar aufs gleiche Objekt zeigt, aber keine Referenz im eigentlichen Sinne ist?
Der Zeiger (Sprich ein Integer der die Speicheradresse des Objektes enthält) wird kopiert.
blub85 schrieb:
Denn bei by_ref2 arbeitet man ja wirklich mit einer Referenz. Ich gebe hier ja wirklich nur die Speicheradresse weiter...
Eine Referenz kann, muss aber nicht eine Entsprechung im Speicher sein, in Gegensatz zu ein Zeiger, der eine Speicheradresse enthält. Je nach Optimierung und Situation kann es sein das eine Referenz ganz entfernt wird (und direkt auf dem Objekt gearbeitet wird).
-
Dine Referenz bei by_ref2 wird durch den Compiler auch durch einen Zeiger realisiert. Ja, es wird bei by_ref eine Kopie erstellt, aber es ist eine Kopie des Zeigers. Und wie viele Zeiger auf ein Objekt zeigen, ist dem Objekt egal. Bitte bringe auch nicht Reference im Sinne von C++ und Reference im Sinne von call-by-reference durcheinander.
-
Was meinst Du denn mit "Reference im Sinne von C++"?
Meinst Du damit sowas:
Foo f;dass f eine Referenz auf das erstellte Objekt ist?
Dine Referenz bei by_ref2 wird durch den Compiler auch durch einen Zeiger realisiert. Ja, es wird bei by_ref eine Kopie erstellt, aber es ist eine Kopie des Zeigers.
Okay. by_ref habe ich soweit kapiert. Der Zeiger wird einfach nochmal kopiert und beide zeigen auf das gleiche Objekt.
Was passiert denn genau, wenn ich by_ref2 aufrufe?? Da wird doch nur mit der übergebenen Adresse gearbeitet, oder? Aber &a ist ja nicht direkt ein Zeiger, sondern eine Referenz... Wo genau, bzw. wie kommt da ein Zeiger ins Spiel?
Danke!!!!
-
blub85 schrieb:
Aber &a ist ja nicht direkt ein Zeiger, sondern eine Referenz... Wo genau, bzw. wie kommt da ein Zeiger ins Spiel?
Ein Pointer hat als Wert auch nur eine Adresse. Wie bereits beschrieben, kann eine Referenz technisch durchaus so aussehen wie ein Pointer und umgekehrt. Was da genau passiert, wird von der Sprache nicht festgelegt. (Damit man das optimieren kann.)
-
Das würde aber ja bedeuten, dass by_ref2 auch einen neuen Pointer anlegt, der auf die gleiche Stelle im Speicher zeigt?
Dann wäre es ja -rein technisch gesehen- kein Unterschied zu by_ref.
Oder?!?
-
Ja, aber bitte schliesse nicht daraus, dass eines von beiden sinnlos sei.
-
Okay, nee, mach ich nicht.

Aber worin liegen da die genauen Unterschiede/Vorteile?
Was mir jetzt spontan einfällt ist, dass ich mit (*p++) den Pointer auf die nächste Stelle zB eines Arrays setzten kann, wobei ich bei &p++ den Wert der Variablen hochsetzen könnte.
Gibts noch weitere Unterschiede??
-
blub85 schrieb:
Was meinst Du denn mit "Reference im Sinne von C++"?
Foo f; // Objekt, nicht Referenz! Foo & g = f; // Referenz, im Sinne eines Aliasnamens, auf f. // Dies kann, muss aber nicht, vom Compiler in einen Zeiger // umgewandelt werden, ebenso könnte der Compiler hier aber auch // einfach f verwenden. // Sprich: Es kann sein das zur Laufzeit hierfür Speicherplatz // (Eine Adresse) reserviert ist, ebenso kann es aber auch gänzlich // wegfallen, da eine C++ Referenz nur ein anderer Name, ein Alias // für das eigentliche Objekt ist. Foo * h; // Eine Speicheradresse die auf ein Objekt des Typs Foo zeigen // kann.blub85 schrieb:
Was passiert denn genau, wenn ich by_ref2 aufrufe?? Da wird doch nur mit der übergebenen Adresse gearbeitet, oder?
Übergebene Adresse wäre ein Zeiger, eine C++ Referenz ist ein anderer Name für das Originalobjekt (und kann wie gesagt unter Umständen, aber nicht zwingend intern als Zeiger umgesetzt werden). Löss dich daher von dem Begriff Adresse für eine Referenz. Die Referenz muss theoretisch keinerlei weiteren Platz zur Laufzeit einnehmen. Ein Zeiger wiederum enthält genau eine Adresse, den ein Zeiger IST nichts anderes als eine Speicheradresse (die ggf. auf ein Objekt zeigt).
-
blub85 schrieb:
Aber worin liegen da die genauen Unterschiede/Vorteile?
Eine C++ Referenz ist der Aliasname für ein konkretes gültiges Objekt, das Objekt kannst du bei einer Referenz nicht tauschen, ebenso muss es ein gültiges Objekt sein (NULL ist unzulässig). Das liegt alleine schon an der Tatsache das eine Referenz theoretisch keinen Speicherplatz zur Laufzeit einnehmen muss (es aber in der Regel dennoch tut, das ist aber Situations- und Compilerabhängig).
Eine C++ Zeiger kann jederzeit auf ein anderes Objekt verweisen, da er nur eine Speicheradresse ist, die beliebig geändert werden kann. Somit ist auch ein NULL-Wert zulässig.
Von der Benutzung her sind Referenzen meist angenehmer. Ich kenne viele die Zeiger nur dann verwenden, wenn NULL-Werte zulässig sind, und ansonsten Referenzen verwenden.
-
Eine C++ Referenz ist der Aliasname für ein konkretes gültiges Objekt, das Objekt kannst du bei einer Referenz nicht tauschen, ebenso muss es ein gültiges Objekt sein (NULL ist unzulässig).
int& ri = *reinterpret_cast<int*>(0);
-
Ethon schrieb:
int& ri = *reinterpret_cast<int*>(0);
Speicherzugriffsfehler.
EDIT: Scheinbar doch nicht:
include <iostream> int main() { int& ri = *reinterpret_cast<int*>(0); std::cout << (&ri == 0) << std::endl; }Ausgabe:
1

-
pyhax schrieb:
Ethon schrieb:
int& ri = *reinterpret_cast<int*>(0);
Speicherzugriffsfehler.
Nö, wieso?
-
Ätsch.
http://ideone.com/DbrWn
-
Aber ist das erlaubt? Nicht UB oder IB?
-
pyhax schrieb:
Aber ist das erlaubt? Nicht UB oder IB?
Doch UB, aber das heißt ja gerade nicht, dass der Compiler unbedingt dafür sorgen muss, dass normalerweise harmloser Code plötzlich Speicherfehler erzeugen muss.
-
Bashar schrieb:
pyhax schrieb:
Aber ist das erlaubt? Nicht UB oder IB?
Doch UB, aber das heißt ja gerade nicht, dass der Compiler unbedingt dafür sorgen muss, dass normalerweise harmloser Code plötzlich Speicherfehler erzeugen muss.
So meinte ich das auch gar nicht. Ich dachte nur, es würde einen Speicherfehler verursachen, weil (int)(0) ja einen Nullpointer dereferenziert. Und als es dann keinen Speicherfehler gab, wollte ich wissen, ob es vlt irgend eine Klausel im Standard gibt, dass die Dereferenzierung eines Nullpointers bei der Initialisierung eine Referenz erlaubt ist.
-
Es ist keine richtige Dereferenzierung, da ja auf niedrigerer Ebene eine Referenz nichts anderes als ein Zeiger ist. Unter der Haube wurde da eigentlich nur der Wert eines Zeigers in eine Referenz kopiert.
Dereferenziert muss erst werden, sobald auf den Wert zugegriffen wird. Und da hättes BUMM gemacht:
int& ri = *static_cast<int*>(0); std::cout << ri + 7; // BUMM