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. data
moeten 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_string
accessors [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 elkei
in[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 waardecharT();
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::string
bewerkingen – b.v. iteratie, aaneenschakeling en elementmutatie – hebben de nulterminator niet nodig. Tenzij u de string
doorgeeft 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::substr
kan 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_str
aanroept 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::data
een 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_str
of data
aanroept.
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*