web-dev-qa-db-fra.com

string c_str () vs data ()

J'ai lu à plusieurs endroits que la différence entre c_str() et data() (dans STL et d'autres implémentations) est que c_str() est toujours terminée par null tandis que data() n'est pas. Pour autant que je l'ai vu dans les implémentations réelles, ils font la même chose ou data() appelle c_str().

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

92
leon

La documentation est correcte. Utilisez c_str() si vous voulez une chaîne terminée par null.

Si les implémenteurs préfèrent implémenter data() en termes de c_str() vous n'avez pas à vous inquiéter, utilisez toujours data() si vous ne le faites pas pas besoin que la chaîne soit terminée par null, dans certaines implémentations, il peut s'avérer plus performant que c_str ().

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

Extra : Dans C++ 11 et suivants, les deux fonctions doivent être identiques. c'est-à-dire que data doit maintenant se terminer par null. Selon cppreference : "Le tableau renvoyé est terminé par null, c'est-à-dire que data () et c_str () remplissent la même fonction."

99
Scott Langham

Dans C++ 11/C++ 0x , data() et c_str() n'est plus différent. Et donc 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 Renvoie: Un pointeur p tel que p + i == &operator[](i) pour chaque i dans [0,size()].


21.4.5 Accès à l'élément basic_string [string.access]

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.

26
mfazekas

Même en sachant que 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é 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 exemple 1.

Vous devez utiliser la méthode .data () lorsque vous utilisez votre chaîne comme 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 réviseurs votre code.

écueil possible avec l'utilisation de .data ()

Le code suivant est incorrect et pourrait provoquer une erreur de segmentation 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 la même chose avec .data () et .c_str ()?

Parce qu'il est plus efficace de le faire. La seule façon de faire en sorte que .data () retourne quelque chose qui ne se termine pas par null, serait d'avoir .c_str () ou .data () copier leur tampon interne, ou d'utiliser simplement 2 tampons. Avoir un seul tampon terminé par null signifie toujours que vous pouvez toujours utiliser un seul tampon interne lors de l'implémentation de std :: string.

18
Brian R. Bondy

Il a déjà été répondu, quelques notes sur le but: Liberté de mise en œuvre.

std::string opérations - par exemple itération, concaténation et mutation d'élément - n'ont pas besoin du terminateur zéro. À moins que vous ne passiez le string à une fonction qui attend une chaîne terminée par zéro, elle peut être omise.

Cela permettrait à une implémentation que des sous-chaînes partagent les données de chaîne réelles: string::substr pourrait contenir en interne une référence aux données de chaîne partagées et à la plage de début/fin, évitant la copie (et l'allocation supplémentaire) des données de chaîne réelles. L'implémentation différerait la copie jusqu'à ce que vous appeliez c_str ou que vous modifiiez l'une des chaînes. Aucune copie ne sera jamais faite si les strigns impliqués sont simplement lus.

(l'implémentation de copie sur écriture n'est pas très amusante dans les environnements multithreads, et les économies de mémoire/allocation typiques 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 ex. une corde (liste chaînée de segments de chaîne). Cela peut améliorer considérablement les opérations d'insertion/remplacement. encore une fois, la liste des segments devrait être réduite à un seul segment lorsque vous appelez c_str ou data.

3
peterchen

Tous les commentaires précédents sont cohérents, mais je voudrais également ajouter qu'à partir de c ++ 17, str.data () retourne un char * au lieu de const char *

2
Nam Burger

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.
2
Mihran Hovsepyan