Referenz auf Rückgabewert?



  • Hi,

    hab 2 Fragen (stehen im Kommentar):

    class foo;
    
    foo& methodRef();
    foo methodVal();
    
    //...
    foo& m = methodRef(); // Frage1: m wird per Copy-Ctor initialisiert, oder?
    foo& v = methodRef(); // Frage2: v IST quasi das Objekt, das returned wurde?
    foo& r = methodVal(); // Frage3: Was passiert hier? Ein foo Objekt wird zurückgegeben
    // und r zeigt auf dieses Objekt. Aber wird das Objekt nach der Zeile zerstört und r zeigt ins Leere? Oder wird das Objekt am Leben gehalten?
    


  • Hier 4 Antworten auf deine 2 (oder 3?) Fragen:

    1. wenn Methodref eine Referenz zurueckgibt, dann bitte nur eine auf ein Objekt, was bereits ausserhalb des Methodenaufrufs existiert. Andernfalls ist die Referenz sofort nach verlassen der Methode ungueltig, also sowas bitte nicht:
    foo& methodRef()
    {
      foo f;
      return f; //da die methode eine referenz zurueckgeben soll, wird hier auch nur eine referenz auf f erzeugt und zurueckgegeben.
    } //f zerstoert, referenz sofort ungueltig
    
    1. m ist eine Referenz und kein Objekt, daher wird nichts initialisiert, also auch nicht mit copy-ctor. Referenzen zeigen auf bereits bestehende Objekte, es wird nichts neu erzeugt.
    2. v ist eine referenz auf das objekt, das returned wurde. Um genauer zu sein, wurde garkein objekt zurueckgegeben, sondern eine referenz (siehe methodendeklaration). Und v ist gleich dieser referenz, verweist also auf das gleiche Objekt.
      3)richtig, r zeigt in die Wueste.

    And we enter the shady realms of undefined behaviour.



  • Hi,

    die ersten beiden Aufrufe sind ja schonmal identisch, bleiben also nur noch 2 Fälle und in keinem der beiden wird ein Objekt (im hier sichtbaren Code) erzeugt, sondern lediglich eine Referenz an die Rückgabe der Methode gebunden.
    In jedem Fall ist das vermutlich eine hochgradig unsichere (bis verbotene) Geschichte, da die Chance relativ hoch ist, das referenzierte Objekt temporär ist = mit Verlassen der Funktion aufhört zu existieren => die Referenz zeigt "ins Leere".
    Das hängt aber halt davon ab, woher die Rückgabe der Funktion stammt. Folgendes ist z.B. unbedenklich (zumindestens bzgl. dieser Problematik):

    foo& staticReturner() {
       static foo s;
       return s;
    }
    
    foo& newReturner() {
       return *new foo; //produziert i.Allg. Speicherleck
    }
    
    foo& paramReturner(foo& f) { 
       // hier kann f natürlich auch schon auf ein ungültiges foo verweisen,
       // das liegt aber nicht in der Verantwortung der Funktion
       return f;
    }
    

    Mit Deinem ersten Beispiel meintest Du vermutlich

    foo m = methodRef();
    

    und da hättest Du Recht: Dies ist eine Initialisierung via CpyCtor (oder überhaupt einem passenden Ctor).

    Ach ja: "Methoden" nennt man Funktionen eigentlich (höchstens), wenn sie Member einer Klasse sind. 😉

    Gruß,

    Simon2.



  • Zu Frage 1: Nein, CC ist nicht im Spiel. Es wäre ein CC für Referenzen involviert, wenn es denn so etwas als explizites Sprachkonstrukt gäbe.
    zu Frage 2: Nein, nicht wirklich. Es ist und bleibt eine Referenz. Das Objekt selbst muß daher irgend wo in methodRef() noch existieren, andernfalls gibt es undefiniertes Verhalten.
    zu Frage 3: Das ergibt undefiniertes Verhalten, da r mit einem temporären Objekt initialisiert wurden, und dies nachher nicht mehr existiert.



  • Thx!
    Ja, bei m hab ich versehentlich auch ein & geschrieben.



  • In dem Fall wird natuerlich der copy-ctor benutzt. Allerdings geht auch das nur, wenn methodref() eine referenz auf ein gueltiges Objekt liefert. andernfalls ist die Referenz bereits vor dem Aufruf des copy-ctors ungueltig => undefiniertes verhalten.



  • Frage3: das ist kein legales C++. MSVC implementiert diese Situation so dass das zurückgegebene Objekt an die Referenz gebunden wird, d.h. es wird erst zerstört wenn die Referenz aus dem Scope fällt.
    D.h. man könnte genausogut eine Variable anstelle der Referenz verwenden.



  • hustbaer schrieb:

    ...
    D.h. man könnte genausogut eine Variable anstelle der Referenz verwenden.

    Nein: "Man könnte besser eine ..." 😉
    Damit würde man wenigstens dem CpyCtor eine Chance geben. 😉 😃

    Gruß,

    Simon2.


  • Mod

    hustbaer schrieb:

    Frage3: das ist kein legales C++. MSVC implementiert diese Situation so dass das zurückgegebene Objekt an die Referenz gebunden wird, d.h. es wird erst zerstört wenn die Referenz aus dem Scope fällt.
    D.h. man könnte genausogut eine Variable anstelle der Referenz verwenden.

    Um es nochmal zu betonen:

    foo& r = methodVal();
    

    Ist ill-formed nach dem ISO-Standard - muss also diagnostiziert werden und hat kein undefiniertes Verhalten beim Programmablauf. Was bestimmte Compiler an dieser Stelle anders machen, spielt da keine Rolle - im Übrigen kann man msvc++ diesen Unsinn abgewöhnen.

    const foo& r = methodVal();
    

    Ist nach dem Standard erlaubt und verlängert die Lebenszeit des von methodVal zurückgegebenen temporären Objekts, bis r aus dem Scope fällt. Dabei wir die Referenz direkt gebunden und es ist kein CopyCtor involviert.



  • camper schrieb:

    ...

    const foo& r = methodVal();
    

    Ist nach dem Standard erlaubt und verlängert die Lebenszeit des von methodVal zurückgegebenen temporären Objekts, bis r aus dem Scope fällt...

    😮 😮
    Cooool !! wusste ich noch nicht - man lernt NIE aus.
    👍 😋 👍

    Gruß,

    Simon2.



  • camper schrieb:

    hustbaer schrieb:

    Frage3: das ist kein legales C++. MSVC implementiert diese Situation so dass das zurückgegebene Objekt an die Referenz gebunden wird, d.h. es wird erst zerstört wenn die Referenz aus dem Scope fällt.
    D.h. man könnte genausogut eine Variable anstelle der Referenz verwenden.

    Um es nochmal zu betonen:

    foo& r = methodVal();
    

    Ist ill-formed nach dem ISO-Standard - muss also diagnostiziert werden und hat kein undefiniertes Verhalten beim Programmablauf.

    Jo, schon klar, das meinte ich mit "kein legales C++".

    Was bestimmte Compiler an dieser Stelle anders machen, spielt da keine Rolle - im Übrigen kann man msvc++ diesen Unsinn abgewöhnen.

    Ich wollte nur erwähnen warum es mit MSVC geht (was ja beobachtbares Verhalten ist), und was MSVC macht (nämlich im Prinzip dasselbe wie bei der vom Standard ja erlaubten const-ref Variante).

    BTW: man kann es MSVC nur abgewöhnen wenn es einen nicht stört dass man dann windows.h nichtmehr inkludieren kann 😞


Anmelden zum Antworten