Ist der folgende Code (func1 ()) korrekt, wenn er i zurückgeben muss? Ich erinnere mich, dass ich irgendwo gelesen habe, dass es ein Problem gibt, wenn ein Verweis auf eine lokale Variable zurückgegeben wird. Wie unterscheidet es sich von func2 ()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int& i = * new int;
Antworten:
Dieser Code-Ausschnitt:
funktioniert nicht, da Sie einen Alias (eine Referenz) an ein Objekt zurückgeben, dessen Lebensdauer auf den Umfang des Funktionsaufrufs beschränkt ist. Das heißt, sobald
func1()
zurückgegeben wird,int i
stirbt, wird die von der Funktion zurückgegebene Referenz wertlos, da sie jetzt auf ein Objekt verweist, das nicht existiert.Die zweite Version funktioniert, da die Variable im freien Speicher zugeordnet ist, der nicht an die Lebensdauer des Funktionsaufrufs gebunden ist. Sie sind jedoch für
delete
die Zuweisung verantwortlichint
.Normalerweise wird der Zeiger in eine RAII- Klasse und / oder eine Factory-Funktion eingeschlossen, damit Sie ihn nicht
delete
selbst benötigen .In beiden Fällen können Sie einfach den Wert selbst zurückgeben (obwohl mir klar ist, dass das von Ihnen angegebene Beispiel wahrscheinlich erfunden wurde):
Beachten Sie, dass es vollkommen in Ordnung ist, große Objekte auf dieselbe Weise zurückzugeben, wie
func3()
primitive Werte zurückgegeben werden, da heutzutage fast jeder Compiler eine Form der Rückgabewertoptimierung implementiert :Interessanterweise ist das Binden eines Temporärs an eine const- Referenz in C ++ völlig legal .
quelle
int* p = func2(); delete p;
Sie. Wenn Sie nun 'p' löschen, bedeutet dies, dass der "innerhalb" der Funktionsdefinition zugewiesene Speicherfunc2()
ebenfalls gelöscht wurde?func2()
und in der nächsten Zeile außen freigegeben. Es ist jedoch eine ziemlich fehleranfällige Methode, mit Speicher umzugehen, wie ich bereits sagte, dass Sie stattdessen eine Variante von RAII verwenden würden. Übrigens, Sie hören sich an, als würden Sie C ++ lernen. Ich empfehle, ein gutes C ++ - Einführungsbuch zu lesen, aus dem Sie lernen können. Wenn Sie eine Frage haben, können Sie die Frage zum späteren Nachschlagen jederzeit im Stapelüberlauf veröffentlichen. Kommentare sind nicht dazu gedacht, völlig neue Fragen zu stellen.Eine lokale Variable ist der Speicher auf dem Stapel. Dieser Speicher wird nicht automatisch ungültig, wenn Sie den Gültigkeitsbereich verlassen. Von einer tiefer verschachtelten Funktion (höher auf dem Stapel im Speicher) ist der Zugriff auf diesen Speicher absolut sicher.
Sobald die Funktion zurückkehrt und endet, werden die Dinge gefährlich. Normalerweise wird der Speicher bei Ihrer Rückkehr nicht gelöscht oder überschrieben, was bedeutet, dass der Speicher an diesen Adressen noch Ihre Daten enthält - der Zeiger scheint gültig zu sein.
Bis eine andere Funktion den Stapel aufbaut und überschreibt. Aus diesem Grund kann dies für eine Weile funktionieren - und dann plötzlich nicht mehr funktionieren, nachdem ein besonders tief verschachtelter Satz von Funktionen oder eine Funktion mit wirklich großen oder vielen lokalen Objekten diesen Stapelspeicher wieder erreicht hat.
Es kann sogar vorkommen, dass Sie denselben Programmteil wieder erreichen und Ihre alte lokale Funktionsvariable mit der neuen Funktionsvariablen überschreiben. All dies ist sehr gefährlich und sollte stark entmutigt werden. Verwenden Sie keine Zeiger auf lokale Objekte!
quelle
Eine gute Sache, an die Sie sich erinnern sollten, sind diese einfachen Regeln, die sowohl für Parameter als auch für Rückgabetypen gelten ...
Für jeden gibt es eine Zeit und einen Ort. Lernen Sie sie also unbedingt kennen. Lokale Variablen sind, wie Sie hier gezeigt haben, genau das, begrenzt auf die Zeit, in der sie im Funktionsumfang lokal aktiv sind. In Ihrem Beispiel wäre es gleichermaßen falsch gewesen , einen Rückgabetyp von
int*
und eine Rückgabe&i
zu haben. In diesem Fall wären Sie besser dran ...Dies würde den Wert Ihres übergebenen Parameters direkt ändern. Während dieser Code ...
würde nicht. Es würde nur den Wert von
oValue
local in den Funktionsaufruf ändern . Der Grund dafür ist, dass Sie tatsächlich nur eine "lokale" Kopie vonoValue
und nicht sichoValue
selbst ändern würden .quelle