Scope bei return von Variablen
-
loks schrieb:
Du bist anscheinend auf die Propaganda hereingefallen das Referenzen und Zeiger das gleiche sind. Das ist falsch.
Auf Ebene von C++ hast du recht, und daher sehe auch ich Referenzen und Zeiger als etwas gänzlich unterschiedliches an. Gerade auch, um Neulinge nicht zu verwirren. Zudem "sieht" der Programmierer bei einer Referenz nur dessen "Schnittstelle" (Das eine Referenz intern häufig über Zeiger realisiert werden, ändert nichts an der Tatsache das es für den Entwickler irrelevant sein sollte).
cu André
-
Gut, ich nehme an bzw meiner Erfahrung nach, benutze ich, zumindest unter anderem, ein "new" (auch) um diese Dinge wie Lebensdauer explizit zu kontrollieren. Deshalb hab ich keinen Destruktor Aufruf fuer die getNew() Version unmittelbar nach Austritt der Funktion getNew(). Die Frage mit dem Scope stell(t)e ich aber auch um zu erfahren ob es etwa weitere spezifisch Einschraenkungen gibt, im Zugriff, etc.. die mit dem Ort der Erstellung zu tun haben und AUCH dynamisch erstellte Instanzen betrifft?
Ich habe nun eine Version mit einer Klasse statt int erstellt und stelle fest, dass nach jedem Funktionsaustritt (ausser bei getNew()) sofort der Destruktor gerufen wird?! Das finde ich nun beunruhigend. Was bekomme ich denn dann bitte geliefert? Die Referenz auf ein Object das so eben getoetet worden ist?
Ich dachte das Problem - v.a. mit der Lebensdauer von lokalen Objekten - laege eher darin, dass sie "spaetestens wenn die Klasse gekillt wird, damit auch verschwinden." Nun aber muss ich feststellen, dass sie bei Austritt der Funktion einerseits verschwinden, andererseits habe ich aber dann doch eine initialisierte Variable in der aufrufenden Funktion?!
Bitte, erklaert mir vllt einer noch Punkt 1 von oben - warum der Addressunterschied?
-
Fabeltier schrieb:
Ich habe nun eine Version mit einer Klasse statt int erstellt und stelle fest, dass nach jedem Funktionsaustritt (ausser bei getNew()) sofort der Destruktor gerufen wird?! Das finde ich nun beunruhigend.
Das ist genau das Verhalten was man bei Variablen zu erwarten hat die auf dem Stack angelegt werden. Bei der Rückgabe wird hier der Inhalt kopiert. Danach wird die Variable zerstört.
Frankly... Lies Dir mal die Grundlagen über Heap, Stack und Scope durch. Du scheinst da noch erhebliche Wissens- bzw. Verständnislücken zu haben.
-
Sry, hatte uebersehen dass zwischenzeitlich wieder wer geantwortet hatte..
@loks:
Naja, "value" hat eine andere Adresse als "local", ok, "value" ist ja auch eine andere Variable, das nehme ich so hin. Aber was ist dann der Unterschied zwischen:int getSomething()und
int& getSomething()Das waere doch dann im Falle einer lokalen Variable dasselbe oder nicht?!
Muesste nicht eigentlich "value" die addresse von "local" als Inhalt bekommen bei getRef()?Frankly... Lies Dir mal die Grundlagen über Heap, Stack und Scope durch. Du scheinst da noch erhebliche Wissens- bzw. Verständnislücken zu haben.
Vllt sollte ich dazusagen, dass mir die Warnungen, keine Addressen von lokalen statischen Variablen nach draussen zu uebergeben durchaus bekannt sind. Somit vermeide ich diese Situation, wie auch Zeiger auf lokale Variabeln als Uebergabe, eigentlich generell. Aber eig klar, wenn ich in einer Funktion allokiere und in einer anderen denselben Speicher nutze, hab ich ja auch keinen Stress.. war da etwas verwirrt. So wie die Diskussion verlaeuft scheint die Lebensdauer der Variablen wirklich DER einzigste Unterschied zu sein. Bin da wirklich etwas auf der Leitung gestanden und sehe das nun wieder etwas klarer, danke fuer die Erklaerung.
Eine "Verstandnisluecke" aber sehe ich hier trotzdem bei obigem Code und dem Unterschied zwischen dem Rueckgabewert von "int" und "int&". Wenn beides in diesem Fall wirklich dasselbe ist - warum bekomme ich dann hier eine Warnung, dass eine Referenz auf eine lokale Variable uebergeben wird? Bzw, was uebergebe ich denn? Muss das echt noch mal nachlesen...

Danke soweit.
-
Es ist nicht dasselbe.
Beiint getSomething()gibst du eine Kopie deiner lokalen Variablen zurück (kein Problem).
Beiint& getSomething()gibst du eine Referenz auf deine lokale Variable zurück. Das ist ein Problem, da eine Referenz eine Art Platzhalter für eine Variable darstellt, die in deinem Fall nach Aufruf der Funktion nicht mehr existiert.
-
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 aUnd 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.