string c_str() vs. data()

Lesezeit: 2 Minuten

Ich habe an mehreren Stellen gelesen, dass der Unterschied zwischen c_str() und data() (in STL und anderen Implementierungen) ist das c_str() ist immer nullterminiert, während data() ist nicht. Soweit ich in tatsächlichen Implementierungen gesehen habe, tun sie entweder dasselbe oder data() Anrufe c_str().

Was fehlt mir hier? Welches ist in welchen Szenarien richtiger?

string c str vs data
Scott Langham

Die Dokumentation ist korrekt. Verwenden c_str() wenn Sie eine nullterminierte Zeichenfolge wünschen.

Wenn die Implementierer zufällig implementiert haben data() bezüglich c_str() Sie müssen sich keine Sorgen machen, verwenden Sie es trotzdem data() Wenn Sie nicht benötigen, dass der String nullterminiert ist, kann es sich in einigen Implementierungen als besser erweisen als c_str().

Zeichenfolgen müssen nicht unbedingt aus Zeichendaten bestehen, sie können aus Elementen beliebigen Typs bestehen. In diesen Fällen data() ist aussagekräftiger. c_str() ist meiner Meinung nach nur dann wirklich nützlich, wenn die Elemente Ihrer Zeichenfolge zeichenbasiert sind.

Extra: Ab C++11 müssen beide Funktionen gleich sein. dh data muss jetzt nullterminiert werden. Entsprechend cpReferenz: “Das zurückgegebene Array ist nullterminiert, das heißt, data() und c_str() führen die gleiche Funktion aus.”

  • Extra 2: Ab C++17 gibt es jetzt auch eine nicht-konstante Überladung für .data()daher sind sie für nicht konstante Zeichenfolgen nicht mehr gleichwertig.

    – Deduplizierer

    20. Dezember 2018 um 1:22 Uhr

  • Wenn die Daten kein Zeichentyp sind, warum sollten Sie eine Zeichenfolge anstelle von Vektoren oder anderen Containern verwenden?

    – Fayure

    21. April 2021 um 12:05 Uhr

string c str vs data
mfazekas

In C++11/C++0x, data() und c_str() ist nicht mehr anders. Und somit data() muss am Ende auch eine Nullterminierung haben.

21.4.7.1 basic_string Accessoren [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 Gibt zurück: Ein Zeiger p so dass p + i == &operator[](i) für jeden i in [0,size()].


21.4.5 elementzugriff auf basic_string [string.access]

const_reference operator[](size_type pos) const noexcept;

1 Benötigt: pos <= size(). 2 Rücksendungen: *(begin() + pos) if pos < size()sonst eine Referenz auf ein Objekt vom Typ T mit Wert charT(); der Referenzwert darf nicht verändert werden.

  • Was ist, wenn die Zeichenfolge aus Nicht-Zeichendaten besteht, was für Zeichenfolgendaten AFAIK zulässig ist, einschließlich Null?

    – taz

    30. Juli 2013 um 16:51 Uhr

  • @taz Auch beim Speichern von Binärdaten erfordert C ++ 11 dies std::string Zuschlag zuweisen char für einen Nachlauf '\0'. Wenn Sie das tun std::string s("\0");beide s.data()[0] und s.data()[1] werden garantiert zu 0 ausgewertet.

    – bcrist

    15. September 2013 um 7:30 Uhr


  • @bcrist Irgendeine Referenz?

    – John

    25. September 2021 um 3:54 Uhr

1646079011 669 string c str vs data
Brian R. Bondy

Auch wenn Sie gesehen haben, dass sie dasselbe tun oder dass .data() .c_str() aufruft, ist es nicht richtig anzunehmen, dass dies bei anderen Compilern der Fall sein wird. Es ist auch möglich, dass sich Ihr Compiler mit einer zukünftigen Version ändert.

2 Gründe für die Verwendung von std::string:

std::string kann sowohl für Text als auch für beliebige Binärdaten verwendet werden.

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

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

Sie sollten die Methode .c_str() verwenden, wenn Sie Ihren String als Beispiel 1 verwenden.

Sie sollten die .data()-Methode verwenden, wenn Sie Ihren String als Beispiel 2 verwenden. Nicht, weil es in diesen Fällen gefährlich wäre, .c_str() zu verwenden, sondern weil es deutlicher ist, dass Sie mit binären Daten für andere Überprüfungen arbeiten dein Code.

Mögliche Fallstricke bei der Verwendung von .data()

Der folgende Code ist falsch und könnte einen Segfault in Ihrem Programm verursachen:

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

Warum ist es üblich, dass Implementierer .data() und .c_str() dazu bringen, dasselbe zu tun?

Weil es effizienter ist, dies zu tun. Die einzige Möglichkeit, .data() dazu zu bringen, etwas zurückzugeben, das nicht nullterminiert ist, wäre, .c_str() oder .data() ihren internen Puffer kopieren zu lassen oder nur 2 Puffer zu verwenden. Einen einzelnen nullterminierten Puffer zu haben bedeutet immer, dass Sie immer nur einen internen Puffer verwenden können, wenn Sie std::string implementieren.

  • Eigentlich ist der Sinn von .data(), dass es den internen Puffer nicht kopieren soll. Dies bedeutet, dass eine Implementierung kein Zeichen auf \0 verschwenden muss, bis es benötigt wird. Sie möchten niemals zwei Puffer: Wenn Sie .c_str() aufrufen, hängen Sie ein \0 an den Puffer an. .data() kann diesen Puffer immer noch zurückgeben.

    – MSalter

    13. Oktober 2008 um 10:46 Uhr

  • Einverstanden, es wäre lächerlich, 2 Puffer zu verwenden. Woher wissen Sie aber, dass .data dafür gedacht war?

    – Brian R. Bondy

    13. Oktober 2008 um 14:18 Uhr

  • @BrianR.Bondy Ich habe diesen Code ausprobiert: .. auto str = string { “Test \0String!” }; cout << "DATA : " << str.data() << endl; Die Ausgabe ist "Test" und nicht die ganze Zeichenfolge. Was habe ich falsch gemacht?

    – Programmierer

    19. September 2015 um 15:45 Uhr

  • Der letzte Teil ist falsch, data und c_str könnten denselben Puffer verwenden, ohne dass er 0-terminiert ist – c_str könnte beim ersten Aufruf einfach die 0 hinzufügen.

    – Erinnere dich an Monika

    24. März 2018 um 23:54 Uhr

  • Achtung, c++11 hat .data() zu einem Alias ​​für .c_str() gemacht

    – Hansenrik

    2. Juli 2019 um 22:51 Uhr

1646079012 105 string c str vs data
Peterchen

Es wurde bereits beantwortet, einige Anmerkungen zum Zweck: Umsetzungsfreiheit.

std::string Operationen – zB Iteration, Verkettung und Elementmutation – benötigen keinen Nullterminator. Es sei denn, Sie bestehen die string zu einer Funktion, die eine nullterminierte Zeichenkette erwartet, kann sie weggelassen werden.

Dies würde es einer Implementierung ermöglichen, Teilstrings die eigentlichen Stringdaten gemeinsam nutzen zu lassen: string::substr könnte intern einen Verweis auf gemeinsam genutzte Zeichenfolgendaten und den Start-/Endbereich enthalten, wodurch das Kopieren (und zusätzliche Zuordnen) der tatsächlichen Zeichenfolgendaten vermieden wird. Die Implementierung würde die Kopie aufschieben, bis Sie anrufen c_str oder ändern Sie eine der Zeichenfolgen. Es würde niemals eine Kopie erstellt werden, wenn die beteiligten Teilzeichenfolgen nur gelesen werden.

(Copy-on-Write-Implementierung macht in Multithread-Umgebungen nicht viel Spaß, außerdem sind die typischen Speicher-/Zuweisungseinsparungen den komplexeren Code heute nicht wert, daher wird dies selten durchgeführt).


Ähnlich, string::data erlaubt eine andere interne Darstellung, zB ein Seil (verkettete Liste von Saitensegmenten). Dies kann Einfüge-/Ersetzungsvorgänge erheblich verbessern. Auch hier müsste die Liste der Segmente beim Anruf auf ein einzelnes Segment reduziert werden c_str oder data.

Zitat aus ANSI ISO IEC 14882 2003 (C++03-Standard):

    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.

1646079013 707 string c str vs data
Nam Vu

Alle vorherigen Kommentare sind konsistent, aber ich möchte auch hinzufügen, dass str.data() ab c++17 ein char* anstelle von const char* zurückgibt.

892180cookie-checkstring c_str() vs. data()

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy