Ich habe den folgenden Code:
%Vor% Was ich dachte, würde passieren, dass getString()
eine Kopie von str
zurückgibt ( getString()
gibt den Wert zurück); Daher würde die Kopie von str
in main()
"am Leben" bleiben, bis main()
zurückkehrt. Dies würde cStr
point auf einen gültigen Speicherort setzen: die zugrunde liegende char[]
oder char*
(oder was auch immer) der Kopie von str
, die von getString()
zurückgegeben wird, die in main()
verbleibt.
Dies ist jedoch offensichtlich nicht der Fall, da das Programm Müll ausgibt. Also, die Frage ist, wann ist str
zerstört, und warum?
getString()
würde eine Kopie vonstr
zurückgeben (getString()
gibt den Wert zurück);
Es ist richtig.
Somit bleibt die Kopie von
str
inmain()
"am Leben", bismain()
zurückkehrt.
Nein, die zurückgegebene Kopie ist ein temporäres std::string
, das am Ende der Anweisung, in der es erstellt wurde, zerstört wird, d. h. vor std::cout << cStr << std::endl;
. Dann wird cStr
baumeln, Dereferenzierung führt zu UB , alles ist möglich.
Sie können das zurückgegebene temporäre Objekt in eine benannte Variable kopieren oder an eine const
lvalue-Referenz oder rvalue-Referenz binden (die Lebensdauer des temporären Objekts wird verlängert, bis die Referenz den Gültigkeitsbereich verlässt). Wie:
Hier ist eine Erklärung von [The.C ++. Programming.Language.Special.Edition] 10.4.10 Temporäre Objekte [class.temp]] :
Wenn es nicht an eine Referenz gebunden oder zum Initialisieren eines benannten Objekts verwendet wird, a temporäres Objekt wird am Ende des vollständigen Ausdrucks in zerstört wo es erstellt wurde. Ein vollständiger Ausdruck ist ein Ausdruck, der ist kein Teilausdruck eines anderen Ausdrucks.
Die Standard-String-Klasse hat eine Member-Funktion c_str () das gibt ein C-style, Null-terminiertes Array von Zeichen zurück (§3.5.1, §20.4.1). Außerdem ist der Operator + so definiert, dass er eine Kettenverkettung bedeutet. Dies sind sehr nützliche Funktionen für Strings. In Kombination können sie jedoch zu unklaren Problemen führen. Zum Beispiel:
%Vor%Wahrscheinlich ist Ihre erste Reaktion "aber tun Sie das nicht", und ich stimme zu. Wie auch immer, ein solcher Code wird geschrieben, also ist es wert zu wissen, wie es ist interpretiert.
Ein temporäres Objekt der Klassenzeichenfolge wird erstellt, um s1 + s2 zu halten. Als Nächstes wird ein Zeiger auf eine C-artige Zeichenfolge aus diesem Objekt extrahiert. Dann - Am Ende des Ausdrucks - das temporäre Objekt wird gelöscht. Jetzt, Wo wurde die Zeichenfolge im C-Stil zugewiesen? Wahrscheinlich als Teil der temporäres Objekt, das s1 + s2 hält, und dieser Speicher ist nicht garantiert zu existieren, nachdem das temporäre zerstört wurde. Folglich cs Punkte freigegebenen Speicher. Die Ausgabeoperation cout & lt; & lt; cs könnte funktionieren wie erwartet, aber das wäre pures Glück. Ein Compiler kann erkennen und warnen Sie vor vielen Varianten dieses Problems.
Problem hier ist, dass Sie eine temporäre Variable und darüber zurückgeben Diese temporäre Variable, die Sie tun c_str Funktion.
"c_str () - Funktion Gibt einen Zeiger auf ein Array zurück, das einen nullterminierten Wert enthält Sequenz von Zeichen (d. h. eine C-Zeichenfolge), die den Strom darstellt Wert des String-Objekts ( [ Ссылка ).
In diesem Fall zeigt der Zeiger auf den Speicherort, der jetzt nicht vorhanden ist.
%Vor%Lösung: Kopieren Sie Ihr temporäres Objekt ordnungsgemäß in den Speicherort (indem Sie eine lokale Kopie erstellen) und verwenden Sie dann c_str über diesem Objekt.
Wie von anderen erwähnt, verwenden Sie einen Zeiger auf temporär, nachdem er bereits gelöscht wurde - dies ist ein klassisches Beispiel für heap nach der freien Verwendung .
Was ich den Antworten anderer hinzufügen kann, ist, dass Sie eine solche Verwendung leicht mit gcc oder clang Adressen-Sanitizers.
Beispiel:
%Vor%Desinfektionsmittelausgabe:
%Vor%Tags und Links string c++ object-lifetime