Wie lange halten temporäre Objecte



  • Folgende Situation:

    class x {
    ...
    };
    
    x foo(...)
    {
        x result;
        ...
        return x;
    }
    
    void foo2(x& arg1,x& arg2)
    {
        ....
    }
    
    int main(void)
    {
    
        foo2(foo(...),foo(...));
    }
    

    bei den beiden foo() aufrufen wir ja beides mal auf den Rückgabewert eine referenz gebildet. Der Rückgabewert wird aber auf ein temporäres Object
    "übertragen". Meine Frage ist, wie lange lebt dieses Object?

    Würde der Code so klappen.

    die "..." stehen für Sachen die hier eg nur perifär interessant sind.



  • Bis zum Ende von foo2()



  • Das heißt Referenzen auf Rückgabewerte sind nicht schlimm?



  • Kommt immer drauf an



  • Erstmal muss es "return result;" heissen, was aber klar sein sollte 🙂

    Und dann ... du kannst laut Standard ein "unnamed temporary" (wie z.B. den Returnwert) nicht an eine non-const Referenz binden. Ergo wird das nicht kompilieren, ausser mit MSVC mit "language extensions" aufgedreht (was die Defaulteinstellung ist -- ohne "language extensions" kann man nichtmal windows.h inkludieren 😞 ).

    Ist eine (IMHO blöde) Klausel im Standard (über die ich immer wieder selber "stolpere") die "unnsinnigen Code" ala

    class Buffer
    {
        std::string m_s;
    public:
        void Set(std::string const& s) {m_s = s;}
        std::string Get() const {return m_s;}
    };
    
    void foo(std::string& s)
    {
        s = "dingsbums";
    }
    
    void bar()
    {
        Buffer buf;
        // das ist laut Standard illegal:
        foo(buf.Get());
    
        std::cout << buf.Get(); // hier würde NICHT "dingsbums" ausgegeben, da "Get()" ja eine Kopie liefert
    
        // das ist laut Standard lustigerweise legal, hat aber natürlich auch keinen Effekt auf buf.m_s:
        foo(buf.Get() += "");
    }
    

    abfange soll.

    Also mach ne "const &" draus, dann ist das OK. Und dann sagt der Standard (sinngemäss): ein an eine const Referenz gebundenes temporary lebt mindestens so lange wie die const Referenz lebt. Also auf jeden Fall bis das "foo2" in deinem Beispiel "fertig ist".


  • Mod

    Das Ergebnis stimmt (im Wesentlichen) zwar, allerdings ist hier fast Kernaussage falsch oder wird falsch angewandt.

    hustbaer schrieb:

    Und dann ... du kannst laut Standard ein "unnamed temporary" (wie z.B. den Returnwert) nicht an eine non-const Referenz binden.

    Es geht nicht um Temporaries und schon gar nicht darum, ob diese benannt sind oder nicht. Für Zwecke der Initialisierung einer Referenz ist hier wichtig, ob der initialisierende Ausdruck ein Lvalue ist oder nicht. Wenn ja, so kann der Ausdruck sowohl an eine Referenz auf const oder nicht-const (eines referenzkompatiblen Typs) gebunden werden (vorausgesetzt der ausdruck ist selbst nicht konstant). In diesem Falle wird direkt an das Objekt oder ein Subobjekt gebunden. Ist der Ausdruck ein Rvalue, so kann er in jedem Falle nur an eine Referenz auf const gebunden werden und wird dafür möglicherweise kopiert (er muss auf jeden Fall kopierbar sein). Zudem kann jeder Ausdruck (Lvalue oder Rvalue) an eine Referenz auf const durch Copy-Initialisierung eines Temporaries gebunden werden (wenn Referenztyp und Typ des Ausdrucks nicht bereits referenzkompatibel sind). In jedem Falle spielt es keine Rolle, ob es sich um ein Temporary handelt oder nicht.

    Und dann sagt der Standard (sinngemäss): ein an eine const Referenz gebundenes temporary lebt mindestens so lange wie die const Referenz lebt. Also auf jeden Fall bis das "foo2" in deinem Beispiel "fertig ist".

    Die Initialisierung von Funktionsargumenten wird davon nicht erfasst. Hier greift die Grundregel ein, dass Temporaries als letzter Schritt der Auswertung eines (vollständigen)Ausdrucks (und das ist auf jeden Fall nach jedem Funktionsaufruf innerhalb dieses Ausdrucks) zerstört werden. Wäre es anders, hätte man Schwierigkeiten, z.B. mit diesem Fall umzugehen:

    void foo(std::string* s)
    {
        *s = "dingsbums";
    }
    
    void bar()
    {
        foo(&(buf.Get() += ""));
    }
    


  • Ok, sorry.
    Ich hätte da noch 1-2 Fragen dazu, aber ich will den Thread hier nicht nochmehr zuspammen... 🙂


Anmelden zum Antworten