Das ss.str()
temporäre wird zerstört, nachdem die Initialisierung cstr2
abgeschlossen ist. Wenn Sie es also mit drucken cout
, ist die C-Zeichenfolge, die mit diesem std::string
temporären Zeichen verknüpft war, schon lange nicht mehr vorhanden. Sie haben also Glück, wenn es abstürzt und behauptet, und nicht Glück, wenn es Müll druckt oder scheinbar funktioniert.
const char* cstr2 = ss.str().c_str();
Die C-Zeichenfolge, auf die cstr1
verweist, ist jedoch einer Zeichenfolge zugeordnet, die zum Zeitpunkt der Ausführung noch vorhanden ist, cout
sodass das Ergebnis korrekt gedruckt wird.
Im folgenden Code ist der erste cstr
korrekt (ich nehme an, er befindet sich cstr1
im realen Code?). Die zweite druckt die C-Zeichenfolge, die dem temporären Zeichenfolgenobjekt zugeordnet ist ss.str()
. Das Objekt wird am Ende der Auswertung des vollständigen Ausdrucks, in dem es erscheint, zerstört. Der vollständige Ausdruck ist der gesamte cout << ...
Ausdruck. Während die Ausgabe des C-Strings erfolgt, ist das zugehörige String-Objekt weiterhin vorhanden. Denn cstr2
- es ist reine Schlechtigkeit, dass es gelingt. Möglicherweise wählt es intern denselben Speicherort für das neue temporäre Element aus, das es bereits für das zum Initialisieren verwendete temporäre Element ausgewählt hat cstr2
. Es könnte auch abstürzen.
cout << cstr // Prints correctly
<< ss.str().c_str() // Prints correctly
<< cstr2; // Prints correctly (???)
Die Rückgabe von c_str()
wird normalerweise nur auf den internen Zeichenfolgenpuffer verweisen - dies ist jedoch keine Voraussetzung. Die Zeichenfolge könnte einen Puffer bilden, wenn ihre interne Implementierung beispielsweise nicht zusammenhängend ist (das ist gut möglich - aber im nächsten C ++ - Standard müssen Zeichenfolgen zusammenhängend gespeichert werden).
In GCC verwenden Zeichenfolgen Referenzzählung und Copy-on-Write. Sie werden also feststellen, dass das Folgende zutrifft (zumindest bei meiner GCC-Version).
string a = "hello";
string b(a);
assert(a.c_str() == b.c_str());
Die beiden Zeichenfolgen teilen sich hier den gleichen Puffer. Wenn Sie einen von ihnen ändern, wird der Puffer kopiert und jeder hat seine eigene Kopie. Andere String-Implementierungen machen die Dinge jedoch anders.
str()
so implementiert ist, dass RVO einschalten kann (was sehr wahrscheinlich ist), kann der Compiler das Ergebnis direkt erstellen intmp
, die vorübergehende eliding; und jeder moderne C ++ - Compiler wird dies tun, wenn Optimierungen aktiviert sind. Natürlich garantiert die Bind-to-Const-Referenzlösung keine Kopie, daher ist sie möglicherweise vorzuziehen - aber ich dachte, es lohnt sich immer noch zu klären.