132 votes

chaîne de caractères c_str() vs. data()

J'ai lu à plusieurs endroits que la différence entre c_str() y data() (dans la STL et d'autres implémentations) est que c_str() est toujours à terminaison nulle tandis que data() n'est pas. D'après ce que j'ai vu dans les implémentations réelles, ils font soit la même chose, soit data() appelle c_str() .

Qu'est-ce que je rate ici ? Lequel est le plus correct à utiliser dans quels scénarios ?

131voto

Scott Langham Points 17447

La documentation est correcte. Utilisez c_str() si vous voulez une chaîne à terminaison nulle.

Si les responsables de la mise en œuvre ont décidé de mettre en œuvre data() en termes de c_str() vous n'avez pas à vous inquiéter, utilisez toujours data() si vous n'avez pas besoin que la chaîne soit terminée par un caractère nul, dans certaines implémentations, il peut s'avérer plus performant que c_str().

Les chaînes de caractères ne doivent pas nécessairement être composées de données de type caractère, elles peuvent être composées d'éléments de tout type. Dans ces cas data() est plus significative. c_str() n'est à mon avis vraiment utile que lorsque les éléments de votre chaîne de caractères sont basés sur des caractères.

Extra : À partir de C++11, les deux fonctions doivent être identiques. data doivent désormais être terminés par un caractère nul. Selon le Référence cpp : "Le tableau retourné est à terminaison nulle, c'est-à-dire que data() et c_str() remplissent la même fonction."

35voto

mfazekas Points 3024

Sur C++11/C++0x , data() y c_str() n'est plus différente. Et ainsi data() doit également avoir une terminaison nulle à la fin.

21.4.7.1 basic_string accesseurs [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 Retours : Un pointeur p tel que p + i == &operator[](i) pour chaque i en [0,size()] .


21.4.5 Accès à l'élément basic_string [string.access] (chaîne de caractères)

const_reference operator[](size_type pos) const noexcept;

1 Nécessite : pos <= size(). 2 Renvoie : *(begin() + pos) if pos < size() sinon une référence à un objet de type T avec la valeur charT(); la valeur référencée ne doit pas être modifiée.

20voto

Brian R. Bondy Points 141769

Même si vous avez vu qu'ils font la même chose, ou que .data() appelle .c_str(), il n'est pas correct de supposer que ce sera le cas pour d'autres compilateurs. Il est également possible que votre compilateur change avec une future version.

2 raisons d'utiliser std::string :

std::string peut être utilisé à la fois pour du texte et des données binaires arbitraires.

//Example 1
//Plain text:
std::string s1;
s1 = "abc";

//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);

Vous devez utiliser la méthode .c_str() lorsque vous utilisez votre chaîne comme dans l'exemple 1.

Vous devez utiliser la méthode .data() lorsque vous utilisez votre chaîne de caractères comme dans l'exemple 2. Non pas parce qu'il est dangereux d'utiliser .c_str() dans ces cas, mais parce qu'il est plus explicite que vous travaillez avec des données binaires pour les autres personnes qui examinent votre code.

Piège possible avec l'utilisation de .data()

Le code suivant est erroné et pourrait provoquer un défaut de fonctionnement dans votre programme :

std::string s;
s = "abc";   
char sz[512]; 
strcpy(sz, s.data());//This could crash depending on the implementation of .data()

Pourquoi est-il courant que les implémenteurs fassent faire la même chose à .data() et .c_str() ?

Parce qu'il est plus efficace de le faire. La seule façon de faire en sorte que .data() renvoie quelque chose qui ne soit pas à terminaison nulle, serait de faire en sorte que .c_str() ou .data() copient leur tampon interne, ou d'utiliser simplement 2 tampons. Avoir un seul tampon à terminaison nulle signifie que vous pouvez toujours utiliser un seul tampon interne lorsque vous implémentez std::string.

3voto

peterchen Points 21792

Il y a déjà été répondu, quelques notes sur l'objet : La liberté de mise en œuvre.

std::string (par exemple, l'itération, la concaténation et la mutation d'éléments) n'ont pas besoin du terminateur zéro. À moins que vous ne passiez l'option string à une fonction qui attend une chaîne de caractères à terminaison zéro, il peut être omis.

Cela permettrait à une implémentation de faire en sorte que les sous-chaînes partagent les données réelles de la chaîne : string::substr pourrait contenir en interne une référence aux données de chaîne partagées, ainsi que la plage de début/fin, évitant ainsi la copie (et l'allocation supplémentaire) des données de chaîne réelles. L'implémentation reporterait la copie jusqu'à ce que vous appeliez c_str ou modifier l'une des chaînes de caractères. Aucune copie ne serait jamais faite si les sous-chaînes concernées sont simplement lues.

(la mise en œuvre de la copie sur l'écriture n'est pas très amusante dans les environnements multithreads, et les économies typiques de mémoire/allocation ne valent pas le code plus complexe aujourd'hui, donc c'est rarement fait).


De même, string::data permet une représentation interne différente, par exemple une corde (liste liée de segments de chaîne). Cela peut améliorer les opérations d'insertion/remplacement de manière significative. Encore une fois, la liste de segments devrait être réduite à un seul segment lorsque vous appelez c_str o data .

2voto

Mihran Hovsepyan Points 4644

Citation de ANSI ISO IEC 14882 2003 (norme C++03) :

    21.3.6 basic_string string operations [lib.string.ops]

    const charT* c_str() const;

    Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements
equal the corresponding elements of the string controlled by *this and whose last element is a
null character specified by charT().
    Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the
returned value as a valid pointer value after any subsequent call to a non-const member function of the
class basic_string that designates the same object as this.

    const charT* data() const;

    Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first
size() elements equal the corresponding elements of the string controlled by *this. If size() is
zero, the member returns a non-null pointer that is copyable and can have zero added to it.
    Requires: The program shall not alter any of the values stored in the character array. Nor shall the program
treat the returned value as a valid pointer value after any subsequent call to a non- const member
function of basic_string that designates the same object as this.

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