72 votes

Est-ce que string::c_str() n'est plus à terminaison nulle en C++11 ?

En C++11 basic_string::c_str est défini comme étant exactement le même que basic_string::data qui est à son tour défini comme étant exactement le même que *(begin() + n) y *(&*begin() + n) (lorsque 0 <= n < size() ).

Je ne trouve rien qui exige que la chaîne de caractères ait toujours un caractère nul à sa fin.

Est-ce que cela signifie que c_str() n'est plus garantie de produire une chaîne de caractères à terminaison nulle ?

80voto

Mikhail Glushenkov Points 10348

Les chaînes de caractères doivent désormais utiliser des tampons à terminaison nulle en interne. Regardez la définition de operator[] (21.4.5) :

Exige : pos <= size() .

Les retours : *(begin() + pos) si pos < size() sinon une référence à un objet de type T avec valeur charT() ; la valeur référencée ne doit pas être modifiée.

En regardant en arrière c_str (21.4.7.1/1), nous voyons qu'il est défini en termes de operator[] :

Les retours : Un pointeur p de sorte que p + i == &operator[](i) pour chaque i en [0,size()] .

Et les deux c_str y data doivent être O(1), de sorte que l'implémentation est effectivement forcée d'utiliser des tampons à terminaison nulle.

De plus, comme David Rodríguez - dribeas fait remarquer dans les commentaires, l'exigence de la valeur de retour signifie également que vous pouvez utiliser &operator[](0) comme un synonyme de c_str() donc le caractère nul de fin doit se trouver dans le même tampon (puisque *(p + size()) doit être égal à charT() ) ; cela signifie également que même si le terminateur est initialisé paresseusement, il n'est pas possible d'observer le tampon dans l'état intermédiaire.

23voto

sehe Points 123151

En fait, il est vrai que la nouvelle norme stipule que .data() et .c_str() sont désormais synonymes. Cependant, elle ne dit pas que .c_str() n'est plus terminé par zéro :)

Cela signifie simplement que vous pouvez désormais compter sur le fait que .data() est également terminé par zéro.

Le document N2668 définit les membres c_str() et data() de std::basic_string de la manière suivante comme suit :

 const charT* c_str() const; 
 const charT* data() const; 

Les retours : Un pointeur sur l'élément initial d'un tableau de longueur variable. size() + 1 dont les premiers éléments size() sont égaux aux éléments correspondants correspondants de la chaîne contrôlée par *this et dont le dernier élément est un caractère caractère nul spécifié par charT().

Requiert : Le programme ne doit modifier aucune des valeurs stockées dans le tableau de caractères.

Notez que cela ne PAS signifie que toute chaîne std::valide peut être traitée comme une chaîne C, car std::string peut contenir des nuls intégrés, qui mettront fin prématurément à la chaîne C lorsqu'elle est utilisée directement comme un const char*.

Addendum :

Je n'ai pas accès à la publication actuelle. spécification finale de C++11 mais il semble que cette formulation ait été abandonnée quelque part dans l'historique des révisions de la spécification : par exemple http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

§ 21.4.7 basic_string opérations sur les chaînes de caractères [string.ops]

§ 21.4.7.1 accesseurs basic_string [string.accessors]

     const charT* c_str() const noexcept;
     const charT* data() const noexcept;
  1. Les retours : Un pointeur p tel que p + i == &operator[](i) pour chaque i en [0,size()] .
  2. Complexité : temps constant.
  3. Requiert : Le programme ne doit modifier aucune des valeurs stockées dans le tableau de caractères.

10voto

CashCow Points 18388

L'"histoire" est la suivante : il y a longtemps, lorsque tout le monde travaillait dans des threads uniques, ou du moins lorsque les threads étaient des travailleurs avec leurs propres données, ils ont conçu une classe de chaîne pour C++ qui rendait la manipulation des chaînes plus facile qu'auparavant, et ils ont surchargé l'opérateur+ pour concaténer les chaînes.

Le problème était que les utilisateurs faisaient quelque chose comme :

s = s1 + s2 + s3 + s4;

et chaque concaténation créait un temporaire qui devait implémenter une chaîne de caractères.

C'est pourquoi quelqu'un a eu l'idée d'une "évaluation paresseuse", de sorte qu'en interne, vous pourriez stocker une sorte de "corde" avec toutes les chaînes jusqu'à ce que quelqu'un veuille les lire comme des chaînes C, auquel cas vous changeriez la représentation interne en un tampon contigu.

Cela a résolu le problème ci-dessus mais a causé un tas d'autres maux de tête, en particulier dans le monde multithread où l'on s'attendait à ce qu'une opération .c_str() soit en lecture seule / ne change rien et donc pas besoin de verrouiller quoi que ce soit. Le verrouillage interne prématuré dans l'implémentation de la classe juste au cas où quelqu'un le ferait en multithread (alors qu'il n'y avait même pas de standard de threading) n'était pas non plus une bonne idée. En fait, il était plus coûteux de faire quelque chose de ce genre que de simplement copier le tampon à chaque fois. La même raison pour laquelle l'implémentation "copy on write" a été abandonnée pour les implémentations de chaînes de caractères.

Faisant ainsi .c_str() Une opération véritablement immuable s'est avérée être la chose la plus sensée à faire, mais pouvait-on s'y fier dans une norme qui tient compte des threads ? La nouvelle norme a donc décidé d'indiquer clairement que c'est possible et que la représentation interne doit donc contenir le terminateur nul.

2voto

James Kanze Points 96599

Bien vu. Il s'agit certainement d'un défaut de la norme récemment adoptée ; je suis sûr qu'il n'y avait pas d'intention de casser tout le code qui utilise actuellement la norme c_str . Je suggérerais un rapport de défaut, ou au moins de poser la question en comp.std.c++ (qui finira généralement devant la commission si elle concerne un défaut).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X