Le ss.str()
temporaire est détruit une fois l'initialisation de cstr2
est terminée. Ainsi, lorsque vous l'imprimez avec cout
, la chaîne C qui était associée à ce std::string
temporaire a longtemps été détruite, et vous aurez donc de la chance si elle se bloque et s'affirme, et pas de chance si elle imprime des déchets ou semble fonctionner.
const char* cstr2 = ss.str().c_str();
La chaîne C vers laquelle cstr1
pointe, cependant, est associée à une chaîne qui existe toujours au moment où vous effectuez le cout
- donc elle imprime correctement le résultat.
Dans le code suivant, le premier cstr
est correct (je suppose que c'est cstr1
dans le vrai code?). La seconde imprime la chaîne C associée à l'objet chaîne temporaire ss.str()
. L'objet est détruit à la fin de l'évaluation de l'expression complète dans laquelle il apparaît. L'expression complète est l' cout << ...
expression entière - ainsi, tant que la chaîne C est sortie, l'objet chaîne associé existe toujours. Car cstr2
- c'est de la pure méchanceté qu'elle réussit. Il choisit très probablement en interne le même emplacement de stockage pour le nouveau temporaire qu'il a déjà choisi pour le temporaire utilisé pour l'initialisation cstr2
. Cela pourrait aussi bien s'écraser.
cout << cstr // Prints correctly
<< ss.str().c_str() // Prints correctly
<< cstr2; // Prints correctly (???)
Le retour de c_str()
pointera généralement simplement vers le tampon de chaîne interne - mais ce n'est pas obligatoire. La chaîne pourrait constituer un tampon si son implémentation interne n'est pas contiguë par exemple (c'est bien possible - mais dans le prochain standard C ++, les chaînes doivent être stockées de manière contiguë).
Dans GCC, les chaînes utilisent le comptage de références et la copie sur écriture. Ainsi, vous constaterez que ce qui suit est vrai (c'est le cas, du moins sur ma version GCC)
string a = "hello";
string b(a);
assert(a.c_str() == b.c_str());
Les deux chaînes partagent le même tampon ici. Au moment où vous changez l'un d'eux, le tampon sera copié et chacun conservera sa copie séparée. Cependant, d'autres implémentations de chaînes font les choses différemment.
str()
est implémentée de telle sorte que RVO puisse démarrer (ce qui est très probable), le compilateur est autorisé à construire le résultat directement entmp
, élimination du temporaire; et tout compilateur C ++ moderne le fera lorsque les optimisations sont activées. Bien sûr, la solution bind-to-const-reference garantit l'absence de copie, donc peut-être préférable - mais j'ai pensé que cela méritait encore d'être clarifié.