string c_str() vs. data()

Ik heb op verschillende plaatsen gelezen dat het verschil tussen c_str()en data()(in STL en andere implementaties) is dat c_str()wordt altijd null beëindigd terwijl data()dat niet is.
Voor zover ik heb gezien in daadwerkelijke implementaties, doen ze hetzelfde of data()roept c_str()aan.

Wat mis ik hier?
Welke is het meest correct om te gebruiken in welke scenario’s?


Antwoord 1, autoriteit 100%

De documentatie is correct. Gebruik c_str()als je een null beëindigde tekenreeks.

Als de uitvoerders data()hebben geïmplementeerd in termen van c_str()hoef je je geen zorgen te maken, gebruik nog steeds data()als je de string niet op null wilt beëindigen, in sommige implementaties kan het beter blijken te presteren dan c_str().

strings hoeven niet per se te zijn samengesteld uit karaktergegevens, ze kunnen zijn samengesteld met elementen van elk type. In die gevallen is data()zinvoller. c_str()is naar mijn mening alleen echt nuttig als de elementen van je string op karakters zijn gebaseerd.

Extra: vanaf C++11 moeten beide functies hetzelfde zijn. d.w.z. datamoeten nu op nul worden beëindigd. Volgens cppreference: “De geretourneerde array is null-terminated, dat wil zeggen , data() en c_str() voeren dezelfde functie uit.”


Antwoord 2, autoriteit 26%

In C++11/C++0x, data()en c_str()is niet langer verschillend. En dus moet data()ook een null-beëindiging hebben aan het einde.

21.4.7.1 basic_stringaccessors [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 Retourneert: Een pointer p zodanig dat p + i == &operator[](i)voor elke iin [0,size()].


21.4.5 basic_string elementtoegang [string.access]

const_reference operator[](size_type pos) const noexcept;

1 Vereist: pos <= size().
2 Geeft als resultaat: *(begin() + pos) if pos < size(), anders een verwijzing naar een object van het type T
met waarde charT();zal de waarde waarnaar wordt verwezen niet worden gewijzigd.


Antwoord 3, autoriteit 16%

Zelfs als je hebt gezien dat ze hetzelfde doen, of dat .data() .c_str() aanroept, is het niet correct om aan te nemen dat dit het geval zal zijn voor andere compilers. Het is ook mogelijk dat uw compiler verandert met een toekomstige release.

2 redenen om std::string:

. te gebruiken

std::string kan worden gebruikt voor zowel tekst als willekeurige binaire gegevens.

//Example 1
//Plain text:
std::string s1;
s1 = "abc";
//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);

Je moet de .c_str() methode gebruiken als je je string als voorbeeld 1 gebruikt.

U moet de methode .data() gebruiken wanneer u uw string als voorbeeld 2 gebruikt. Niet omdat het gevaarlijk is om in deze gevallen .c_str() te gebruiken, maar omdat het explicieter is dat u met binaire gegevens werkt voor anderen die uw code bekijken.

Mogelijke valkuil bij het gebruik van .data()

De volgende code is onjuist en kan een segfault in uw programma veroorzaken:

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

Waarom is het gebruikelijk dat uitvoerders .data() en .c_str() hetzelfde laten doen?

Omdat het efficiënter is om dit te doen. De enige manier om .data() iets terug te geven dat niet op nul is beëindigd, is door .c_str() of .data() hun interne buffer te laten kopiëren, of om gewoon 2 buffers te gebruiken. Het hebben van een enkele null-beëindigde buffer betekent altijd dat u altijd slechts één interne buffer kunt gebruiken bij het implementeren van std::string.


Antwoord 4, autoriteit 2%

Het is al beantwoord, enkele opmerkingen over het doel: Vrijheid van implementatie.

std::stringbewerkingen – b.v. iteratie, aaneenschakeling en elementmutatie – hebben de nulterminator niet nodig. Tenzij u de stringdoorgeeft aan een functie die een tekenreeks met een nulpunt verwacht, kan deze worden weggelaten.

Hierdoor kan een implementatie substrings de daadwerkelijke stringgegevens laten delen: string::substrkan intern een verwijzing bevatten naar gedeelde stringgegevens en het begin/eindbereik, waarbij de kopie (en extra toewijzing) van de daadwerkelijke stringgegevens. De implementatie zou de kopie uitstellen totdat u c_straanroept of een van de tekenreeksen wijzigt. Er zou nooit een kopie worden gemaakt als de betrokken substrings gewoon worden gelezen.

(copy-on-write-implementatie is niet leuk in multithreaded-omgevingen, plus de typische besparingen op geheugen/toewijzing zijn de complexere code van vandaag niet waard, dus het wordt zelden gedaan).


Evenzo staat string::dataeen andere interne representatie toe, b.v. een touw (gekoppelde lijst met stringsegmenten). Dit kan de invoeg-/vervangingsoperaties aanzienlijk verbeteren. nogmaals, de lijst met segmenten zou moeten worden samengevouwen tot een enkel segment wanneer u c_strof dataaanroept.


Antwoord 5, autoriteit 2%

Citaat uit ANSI ISO IEC 14882 2003(C++03-standaard):

   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.

Antwoord 6, autoriteit 2%

Alle eerdere opmerkingen zijn consistent, maar ik zou ook willen toevoegen dat str.data() vanaf c++17 een char* retourneert in plaats van const char*

Other episodes