Warum funktioniert das Aufrufen von std :: string.c_str () für eine Funktion, die einen String zurückgibt, nicht?

8

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?

    
Fake Jake 14.03.2016, 06:15
quelle

3 Antworten

18
  

getString() würde eine Kopie von str zurückgeben ( getString() gibt den Wert zurück);

Es ist richtig.

  

Somit bleibt die Kopie von str in main() "am Leben", bis main() 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:

%Vor%

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.

    
songyuanyao 14.03.2016, 06:18
quelle
4

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.

    
user258367 14.03.2016 06:38
quelle
1

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%     
Patryk 27.09.2016 06:41
quelle

Tags und Links