Scope bei return von Variablen



  • Fabeltier schrieb:

    Aber was ist dann der Unterschied zwischen:

    int getSomething()
    

    und

    int& getSomething()
    

    Das waere doch dann im Falle einer lokalen Variable dasselbe oder nicht?!

    NEIN.

    Jede lokale Variable auf dem Stack wird am Ende des umgebenden Scoped zerstört. Dabei ist es egal ob es nun ein Zeiger, ein Integer etc. ist.

    Im ersten Fall gibst du aber eine Kopie zurück, im Zweiten versuchst du einen Alias (siehe gleich unten) auf die lokale Variable zurückzugeben. Eine Kopie ist in der Regel unproblematisch sofern das zurückgelieferte Objekt (ob nun int, oder ein Objekt einer Klasse...) eine gültiges Kopierverhalten hat, und die Kopie nicht zu "teuer" ist (Das ist dann aber eine sache von Profiler/Optimierung).

    Eine Referenz, ein Alias (alternativer Name) ist nur ein anderer Name für eine Variable:

    int a = 2;
    int & b = a;
    b = 4; // Ändert a, da nur ein Aliasname für a
    

    Und ein Alias ist nur gültig, wenn der Originalwert gültig ist.

    int getSomething()
    {
        int a = 4;
        return a; // Rückgabe einer Kopie (a selbst wird destruiert)
    }
    
    int& getSomething()
    {
        int a = 4;
        return a; // Rückgabe eines Alias, der aber ungültig ist, da a destruiert wird
    }
    
    // Als Ergänzung:
    int * getSomething()
    {
        int * a = new int(4);
        return a; // Rückgabe einer Kopie (!) des Zeigers a
        // Der allozierte Bereich ist davon unbetroffen da der Heap nicht automatisch
        // gelöscht wird. Wenn du innerhalb der Funktion die Adresse vom Zeiger
        // (nicht die des allozierten Bereiches) ausgibst, und an der aufrufenden
        // stelle ebenso, wirst du sehen das es unterschiedliche Zeiger sind, die
        // beide aber auf die gleiche Adresse verweisen!
    }
    

    cu André



  • Fabeltier schrieb:

    So wie die Diskussion verlaeuft scheint die Lebensdauer der Variablen wirklich DER einzigste Unterschied zu sein.

    Obwohl die Beobachtung soweit richtig ist stimmt die Schlußfolgerung nicht. es ist ein _erheblicher_ Unterschied ob eine Variable auf dem Stack oder auf dem Heap angelegt wird. Die Sache mit der Lebensdauer ist ein Symptom, keine Ursache davon.

    Deine Verständnisprobleme zum Thema Scope dürften darin liegen das Du nicht weist was ein Stack eigendlich ist und wie er funktioniert. Daher: Nachlesen, lernen.



  • Rückgabe eines Alias, der aber ungültig ist, da a destruiert wird

    Das eine Referenz ein "Alias" darstellt war mir bekannt - nur..
    im Fall von getRef() wird ja offensichtlich eine Kopie des Inhaltes gemacht. "value" und "local" bleiben ja unterschiedliche Variablen mit unterschiedlichen Adressen, richtig? Was auch logisch zu sein scheint, da eine Referenz auf etwas zurueckzugeben, was nicht mehr existiert, sinnlos ist. Es ist schliesslich kein Zeiger, den man auch auf NULL testen koennte. Richtig?

    Gut, worin liegt also nun der Unterschied zwischen der Rueckgabe eines Wertes oder einer Referenz, die wie ein Wert behandelt wird?

    Sorry, dass ist es eigentlich was ich hier nicht ganz verstehe, was mich zu weilen auf dem Schlauch stehen laesst und mich den Scope von alociertem Speicher ebenfalls anzweifeln lies. Stack und Heap sind mir eigentlich nicht fremd, lese es aber nochmal nach, danke. 🙂



  • Im Falle von

    int funktion()
    {
       int a = 10;
       return a;
    }
    
    int b = funktion();
    

    kann man sich die Zuweisung an b in etwa so vorstellen:

    • Die Funktion wird aufgerufen
    • Der Werte von a wird in eine (temporäre) Kopie gesteckt, und die Funktion wird verlassen. a wird dabei gelöscht
    • Der Wert aus die Kopie von a wird b zugewiesen
    • Die Kopie wird zerstört

    Bei

    int& funktion()
    {
       int a = 10;
       return a;
    }
    
    int b = funktion();
    

    läuft das anders ab:

    • Die Funktion wird aufgerufen
    • a IST der Rückgabewert. Die Funktion wird verlassen, a wird zerstört. Der Rückgabewert denkt noch er wäre a, aber a gibts nicht mehr
    • Der Rückgabewert wird an b übergeben, aber da der Rückgabewert eigentlich a ist, und a nicht mehr da ist, passiert hier Schrott


  • Und was ist mit:

    int funktion()
    {
      int a = 10;
      return a;
    }
    
    const int& b = funktion();
    

    😉



  • David_pb schrieb:

    Und was ist mit:

    int funktion()
    {
      int a = 10;
      return a;
    }
    
    const int& b = funktion();
    

    😉

    Da wird das temporäre Objekt an die Referenz gebunden und durch den Scope der Referenz am Leben gehalten. Das war aber im Kontext der Threads unnötig und verwirrt mit Sicherheit nur.



  • Ich finde es passt ziemlich genau in den "Thread-Kontext"... Das es diverse Poster verwirren könnte kann gut sein.



  • Danke Tachyon fuer die ausfuehrliche Erklaerung. 🙂



  • [klugscheiss]In C++ gibt's keinen Stack, es gibt nur Objekte mit automatic storage duration [/klugscheiss]
    *duck und weg*



  • hustbaer schrieb:

    [klugscheiss]In C++ gibt's keinen Stack, es gibt nur Objekte mit automatic storage duration [/klugscheiss]
    *duck und weg*

    Ich fände das gar nicht schlecht, wenn sich diese Formulierung/Sichtweise ein wenig verbreiten würde. Das würde nämlich Vieles schon im Ansatz (er)klären ...
    Allerdings ist es nicht so einfach, die Gewohnheit, von "Stackvariablen" zu reden, aufzubrechen...
    ... gerade auch, weil es eben schnell als klugscheisserei missverstanden wird.

    Gruß,

    Simon2.


Anmelden zum Antworten