Call by value, call by reference



  • 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?





  • 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
    

  • Mod

    Es ist natürlich trotzdem undefiniert ohne Ende, nicht dass hier ein falscher Eindruck entsteht. Eine Referenz muss nicht durch Pointer implementiert sein, sie muss nicht einmal eine Adresse oder überhaupt irgendeine Art von Wert haben. Und das gezeigte ist auch keine echte Nullreferenz, da es bei der kleinsten Berührung explodiert, sondern einfach ein bisschen Klugscheißen und zum Denken anregen.


Anmelden zum Antworten