Casting c_str () funktioniert nur für kurze Strings

7

Ich benutze eine C-Bibliothek in C ++ und habe einen Wrapper geschrieben. An einem Punkt muss ich eine std::string in eine c-style Zeichenfolge konvertieren. Es gibt eine Klasse mit einer Funktion, die eine Zeichenfolge zurückgibt. Die Rückgabe der zurückgegebenen Zeichenfolge funktioniert, wenn die Zeichenfolge kurz ist, andernfalls nicht. Hier ist ein einfaches und reduziertes Beispiel, das das Problem veranschaulicht:

%Vor%

Wenn Sie die obige Datei ausführen, wird dies auf der Konsole angezeigt:

  

castString:

Wenn ich hingegen die Kommentare zu someString vertausche, druckt es

korrekt
  

castString: Hallo

Wie ist das möglich?

    
Cat 14.03.2016, 17:02
quelle

5 Antworten

16

Sie rufen c_str für ein temporäres String-Objekt auf, das durch die% member-Funktion getString() neu ausgerichtet wurde. Der von c_str() zurückgegebene Zeiger ist nur so lange gültig, wie das ursprüngliche Zeichenfolgenobjekt existiert. Am Ende der Zeile, der Sie castString zuweisen, ist es also ein Dangling-Zeiger. Offiziell führt dies zu undefiniertem Verhalten.

Warum funktioniert das für kurze Saiten? Ich vermute, dass Sie die Auswirkungen der Short String Optimization sehen, einer Optimierung, bei der die Zeichendaten für Strings mit weniger als einer bestimmten Länge innerhalb der Bytes des String-Objekts selbst und nicht im Heap gespeichert werden. Es ist möglich, dass die temporäre Zeichenfolge, die zurückgegeben wurde, auf dem Stapel gespeichert wurde. Wenn sie bereinigt wurde, sind keine Zuordnungen aufgetreten und der Zeiger auf das abgelaufene Zeichenfolgenobjekt enthält weiterhin die alten Zeichenfolgenbytes. Dies scheint mit dem übereinzustimmen, was Sie sehen, aber es bedeutet immer noch nicht, dass Sie eine gute Idee haben. : -)

    
templatetypedef 14.03.2016, 17:08
quelle
6

box.getString() ist ein anonymes temporäres . c_str() gilt nur für die Länge der Variablen.

In Ihrem Fall wird also c_str() ungültig gemacht bis Sie zu std::cout gelangen. Das Verhalten beim Lesen des Zeigerinhalts ist undefiniert .

(Interessanterweise ist das Verhalten Ihrer kurzen Zeichenfolge möglicherweise anders, da std::string kurze Zeichenfolgen auf andere Weise speichert.)

    
Bathsheba 14.03.2016 17:05
quelle
5

box.getString() erzeugt eine temporäre. Wenn Sie c_str() aufrufen, erhalten Sie einen Zeiger auf ein temporäres Objekt. Nachdem das temporäre nicht mehr existiert, ist der Zeiger ungültig, ein dangling pointer .

Das Verwenden eines freien Zeigers ist ein nicht definiertes Verhalten.

    
Cheers and hth. - Alf 14.03.2016 17:06
quelle
5

Wie Sie nach Wert zurückgeben

box.getString() ist ein temporäres und so

box.getString().c_str() ist nur während des Ausdrucks gültig, dann ist es ein dangling Zeiger.

Sie können das mit

beheben %Vor%     
Jarod42 14.03.2016 17:06
quelle
4

Zunächst einmal hat Ihr Code UB unabhängig von der Länge der Zeichenfolge: Am Ende von

%Vor%

Die von getString zurückgegebene Zeichenfolge wird gelöscht und castString ist ein ungeordneter Zeiger auf den internen Puffer des zerstörten Zeichenfolgenobjekts.

Der Grund, warum Ihr Code für kleine Strings "arbeitet", ist wahrscheinlich Small String Optimization: Kurze Strings werden (gewöhnlich) im String-Objekt selbst gespeichert, anstatt in einem dynamisch zugewiesenen Array gespeichert zu werden. Offensichtlich ist der Speicher weiterhin zugänglich und unverändert in deinem Fall.

    
Baum mit Augen 14.03.2016 17:07
quelle

Tags und Links