warning: taking address of temporary



  • Eine Funktion erwartet als Parameter einen Pointer auf eine Struktur.

    aStruct aFunction1 ( .. )
    {
         aStruct iamtemporary;
         // init von 'iamtemporary'
         return iamtemporary;
    }
    
    void aFunction2 (const aParameter* iamthepointer)
    {
        // Hier wird eine oberflächige Kopie (Da gabs ein englisches wort dazu. gegenteil war deepcopy) vom parameter gemacht. und in der bibliothek wird sie für weitere zwecke verwendet.
    }
    

    aufrufen tu ich es dann so:

    aFunction2(&aFunction1( .. ));
    

    Nun warnt mich der Compiler mit der oben genannten Meldung.
    Ich stehe vollkommen auf dem Schlauch. Wenn ich das mache

    aStruct iamalsotemporary;
    aFunction2(&iamalsotemporary);

    ist ja das objekt auch temporär, wenn 'iamalsotemporary' den Gültigkeitsbereich verlässt. oder nicht? bitte um erklärung irgendwie stehe ich auf der leitung.


  • Mod

    Der Unterschied ist, dass das Objekt beim zweiten Fall immerhin bis zum Verlassen des Scopes lebt, beim ersten Fall aber nur bis zum Ende des Funktionsaufrufes.

    In beiden Fällen ist es natürlich ein Spiel mit dem Feuer, von automatischen Objekten eine flache Kopie (shallow copy) zu machen, aber im ersten Fall merkt das sogar der Compiler.



  • OK

    habe mir jetzt mal den code der library angeschaut weil das echt fail wäre.
    es wird der wert der struktur kopiert, deep copy

    danke für deine antwort!



  • ichstehaufdemschlauch schrieb:

    Nun warnt mich der Compiler mit der oben genannten Meldung.
    Ich stehe vollkommen auf dem Schlauch. Wenn ich das mache

    aStruct iamalsotemporary;
    aFunction2(&iamalsotemporary);

    ist ja das objekt auch temporär, wenn 'iamalsotemporary' den Gültigkeitsbereich verlässt. oder nicht? bitte um erklärung irgendwie stehe ich auf der leitung.

    vielleicht noch interessant zu wissen: in diesem fall erzeugst du kein temporäres objekt, sondern eines auf dem stack (ein "automatisches" objekt).
    der unterschied zwischen temporaries und auto-objekten liegt darin, dass automatische objekte bis zum ende des gerade gültigen scopes leben, wie schon SeppJ erwähnt hat; temporäre objekte leben *nur* bis ans ende des aktuellen ausdrucks (bis zum ";").

    bei dem ausdruck:

    int foo () ; 
    //...
    int x;
    x = foo ();
    

    liefert dir foo ein temporäres objekt vom typ int, das in x hineinkopiert wird.

    außerdem sind temporäre objekte r-values, und an r-values können nur konstante referenzen binden:

    int& y = foo(); //fehler: versuch, ein r-value an eine nicht-konstante referenz zu binden
    const int& z = foo(); //ist ok!
    

    in letzterem fall bleibt das temporäre objekt bestehen, bis die referenz zerstört wird (und da eine referenz immer automatisch am stack erzeugt wird: bis zum ende des scopes).

    in deinem beispiel versuchst du aber, den adressoperator auf ein rvalue anzuwenden, was nicht erlaubt ist. "rvalue" ist aber keine eigenschaft des (temporären) objekts. prinzipiell ist es also nicht verboten, die adresse eines temporären objekts zu bestimmen, du musst auf das temporäre objekt nur als lvalue zugreifen:

    aStruct aFunction1 ( .. )
    {
         aStruct iamtemporary;
         // init von 'iamtemporary'
         return iamtemporary;
    }
    
    void aFunction2 (const aParameter* iamthepointer)
    {
        // ...
    }
    
    //...
    aStruct const* ptr (aStruct const& x)
    {
       //x ist ein lvalue - also:
       return &x;
    }
    
    //...
    aFunction2(ptr(aFunction1()));
    

    eine flache kopie zu machen impliziert an dieser stelle außerdem, dass es sich um eine resource handelt, die am besten in einer richtigen klasse mit konstruktor und destruktor (RAII) gehandhabt werden sollte. bei einer externen library, die aStruct bereitstellt und RAII nicht kann, wäre eine wrapper-klasse wohl empfehlenswert.

    lg



  • hoppla, meinte natürlich: "nur konstante referenzen können an temporäre objekte binden" (nicht an "rvalues")


  • Mod

    kunststudent schrieb:

    hoppla, meinte natürlich: "nur konstante referenzen können an temporäre objekte binden" (nicht an "rvalues")

    Warum? Vorher war es besser.

    kunststudent schrieb:

    bei dem ausdruck:

    int foo () ; 
    //...
    int x;
    x = foo ();
    

    liefert dir foo ein temporäres objekt vom typ int, das in x hineinkopiert wird.

    Hier existiert keinerlei temporäres Objekt. Der Rückgabewert von foo ist skalar, und skalare rvalues sind keine Objekte, erst recht nicht temporär.

    kunststudent schrieb:

    außerdem sind temporäre objekte r-values

    Nicht ganz, auch wenn es praktisch Haarspalterei ist. Exceptionobjekte sind temporäre Objekte und sie können auch an nicht-const-Referenzen gebunden werden. Die Umkehrung ist allerdings wahr: Sofern rvalues auf Objekte verweisen, handelt es sich dabei immer um temporäre Objekte.

    kunststudent schrieb:

    und an r-values können nur konstante referenzen binden

    Richtig, d.h. die Referenz bindet natürlich an das Objekt, auf das das rvalue (=der Ausdruck) verweist, nicht den Ausdruck als solchen.



  • ich fand mich in dem zwiespalt, das "auf das das rvalue verweist" entsprechend auszudrücken: bindet die referenz an das rvalue oder das temporäre objekt? natürlich auf das objekt, auf das das rvalue verweist 🙂

    wo kann ich das mit den skalaren typen nachlesen?


Anmelden zum Antworten