const Reference an Rückgabewert binden



  • Hiho,

    und zwar habe ich gerade bei der Suche nach etwas anderem folgendes entdeckt:

    string foo() { return "hello"; }
    int main() 
    {
        //below should be the correct one as only const reference can be bind to rvalue(most important const)
        const string& constTem = foo();   
    }
    

    Wieso ist das legaler C++-Code? Welche Regel gilt hier, dass ich eine Referenz auf einen Rückgabewert machen darf, der ja eigentlich nach dem Funktionsaufruf zerstört wird.

    Ich habe mir das Testweise im VC10 nachgebaut:

    class TestRValue
    {
    	public:
    		TestRValue() { std::cout << "constructor called" << std::endl; }
    		~TestRValue() { std::cout << "destructor called" << std::endl; }
    
    };
    
    TestRValue foo() { return TestRValue(); }
    
    int main()
    {
    	foo();
    	const TestRValue& myFoo = foo();
    

    Ausgabe ist:

    constructor called
    destructor called
    constructor called
    

    Warumn klappt das? Aus dem Stehgreif hätte ich gesagt, die Referenz an den Rückgabewert zu binden ist falsch.

    VG

    Pellaeon



  • Die Herleitung, warum das geht, ist recht simpel, allerdings musst du verstehen, dass du nicht auf den Wert bindest, der zerstört wird, sondern auf eine Kopie davon.

    Du kannst einen RValue nicht ändern, eine const Reference ebenfalls nicht. Da das Verhalten konsistent ist, wurde definiert, dass du eine const Reference mit einem RValue initialisieren kannst, wobei intern schon irgendwie eine versteckte Variable existiert, für welche die Referenz zur Laufzeit steht.

    Das heisst:

    const int &foo = bar();
    

    ist äquivalent zu:

    int bar_ = bar(); // das siehst du nicht...
    const int &foo = bar_;
    

  • Mod

    (12.2/5)
    Die Lebenszeit eines temporären Objektes, das an eine Referenz gebunden wird, verlängert sich für die Dauer der Lebenszeit der Referenz, es sei denn,
    - bei der Referenz handelt es sich um ein Member einer Klasse, die in der ctor-Initialisierungsliste mit einem temporären Objekt initialisiert wird, das Objekt lebt dann nur bis zum Ende des Konstruktors, oder
    - wenn bei einem Funktionsaufruf ein Funktionsargument an einen Referenzparameter gebunden wird, das Objekt lebt dann für die Dauer des vollständigen Ausdruckes, der den Funktionsaufruf enthält, oder
    - ein temporäres Objekt wird beim return an einen Referenzrückgabewert gebunden (das sollte man nie tun), die Lebenszeit verlängert sich in diesem Fall nicht, oder
    - wenn an eine Referenz in einem new-Initialisierer gebunden wird (das geht erst in C++11 und ist im Prinzip eine mit der ctor-Bindung oben verwandte Variante), hier lebt das Objekt wiederum bis zum Ende des vollständigen Ausdruckes.

    "Vollständiger Ausdruck" und "temporäres Objekt" haben in C++ nicht ganz die Bedeutung, die der Wortsinn vermuten lässt, bedürfen also einer Definition.

    @/rant/: Dein Beispiel ist insofern nicht das Gleiche, als der Rückgabewert kein temporäres Objekt darstellt, das wird ja erst durch die Referenzbindung erzeugt. Beim OP ist das anders.



  • Mich würde das auch mal interessieren warum das mit const klappt und ohne const nicht. Eure Aussagen wiedersprachen sich da ein wenig.

    Kann man das vielleicht so verstehen, dass const die Referenz daran hindert sich selbst zu verändern? Sagen wir mal

    int func()
    
    	int i = 10;
    
    	return i;
    }
    

    Und in der main-Funktion folgender Code:

    const int & r = func();
    // int & r = func() // Ohne const geht nicht!
    

    i geht dann "out of scope", wenn func verlassen wird. const macht ja was ein mal deklariertes nicht änderbar. Dann müsste es also heißen, dass i out of scope geht und die Referenz mit const eine Kopie anlegt. Verstehe ich das so richtig?



  • ok, danke für Klärung 🙂



  • inc7 schrieb:

    Mich würde das auch mal interessieren warum das mit const klappt und ohne const nicht.

    Pure Willkür 😉 Früher ging das auch mal ohne const, aber dann ist den C++-Standardisierern aufgefallen, dass es nicht so toll ist, wenn man temporäre Objekte verändern kann. Also haben sie es nur noch für Referenzen auf const erlaubt.



  • Ahh, das ist dann die logischste Begründung. 😃



  • Dass das Konstrukt ungewöhnlich ist, ist klar. Allerdings wird in dem gezeigten Code eine Kommentar zur Erklärung gegeben, der sogar noch länger als die Codezeile ist - und wenn man sich den Code anschaut sieht man gegen ende die etwas mekrwürdige Phrase "most important const". Einmal googlen danach hätte gleich die Erklärung gegeben 😉


Log in to reply