it-swarm.com.de

Zeichenfolge c_str () vs. data ()

Ich habe an mehreren Stellen gelesen, dass der Unterschied zwischen c_str() und data() (in AWL und anderen Implementierungen) darin besteht, dass c_str() immer null ist, während data() ist nicht. Soweit ich in tatsächlichen Implementierungen gesehen habe, tun sie entweder dasselbe oder data() ruft c_str() auf.

Was vermisse ich hier? Welches ist in welchen Szenarien richtiger?

92
leon

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

Wenn die Implementierer zufällig data() in Bezug auf c_str() implementieren, müssen Sie sich keine Sorgen machen, verwenden Sie trotzdem data(), wenn Sie nicht tun Die Zeichenfolge muss nicht mit Null abgeschlossen werden. In einigen Implementierungen hat sie möglicherweise eine bessere Leistung als c_str ().

zeichenfolgen müssen nicht unbedingt aus Zeichendaten bestehen, sondern können aus Elementen beliebigen Typs bestehen. In diesen Fällen ist data() sinnvoller. c_str() ist meiner Meinung nach nur dann wirklich nützlich, wenn die Elemente Ihres Strings zeichenbasiert sind.

Extra : Ab C++ 11 müssen beide Funktionen identisch sein. d.h. data muss nun mit Null terminiert werden. Entsprechend cppreference : "Das zurückgegebene Array ist nullterminiert, dh data () und c_str () führen dieselbe Funktion aus."

99
Scott Langham

In C++ 11/C++ 0x unterscheiden sich data() und c_str() nicht mehr. Daher muss data() auch am Ende 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 Folgendes zurück: Ein Zeiger p, so dass p + i == &operator[](i) für jedes i in [0,size()].


21.4.5 Zugriff auf das basic_string-Element [string.access]

const_reference operator[](size_type pos) const noexcept;

1 Benötigt: pos <= size (). 2 Liefert: *(begin() + pos) if pos < size(), andernfalls wird eine Referenz auf ein Objekt vom Typ T mit dem Wert charT(); der referenzierte Wert nicht geändert.

26
mfazekas

Selbst wenn Sie wissen, dass sie dasselbe tun oder dass .data () .c_str () aufruft, ist es nicht richtig anzunehmen, dass dies für andere Compiler der Fall ist. 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 .c_str () -Methode verwenden, wenn Sie Ihre Zeichenfolge als Beispiel 1 verwenden.

Sie sollten die .data () -Methode verwenden, wenn Sie Ihre Zeichenfolge als Beispiel 2 verwenden. Nicht, weil die Verwendung von .c_str () in diesen Fällen gefährlich ist, sondern weil expliziter ist, dass Sie mit Binärdaten arbeiten, damit andere sie überprüfen dein Code.

Mögliche Gefahr bei Verwendung von .data ()

Der folgende Code ist falsch und kann 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 für Implementierer üblich, dass .data () und .c_str () dasselbe tun?

Weil es effizienter ist, dies zu tun. Die einzige Möglichkeit, .data () zu veranlassen, etwas zurückzugeben, das nicht mit Null abgeschlossen ist, besteht darin, den internen Puffer von .c_str () oder .data () zu kopieren oder nur 2 Puffer zu verwenden. Ein einzelner Puffer mit Null-Abschluss bedeutet immer, dass Sie beim Implementieren von std :: string immer nur einen internen Puffer verwenden können.

18
Brian R. Bondy

Es wurden bereits einige Hinweise zum Zweck beantwortet: Umsetzungsfreiheit.

Operationen std::string - z.B. Iteration, Verkettung und Elementmutation - benötigen Sie keinen Nullterminator. Sofern Sie das string nicht an eine Funktion übergeben, die eine nullterminierte Zeichenfolge erwartet, kann es weggelassen werden.

Dies würde einer Implementierung ermöglichen, dass Teilzeichenfolgen die tatsächlichen Zeichenfolgendaten gemeinsam nutzen: string::substr Könnte intern einen Verweis auf gemeinsam genutzte Zeichenfolgendaten und den Start-/Endbereich enthalten, wodurch das Kopieren (und die zusätzliche Zuordnung) der tatsächlichen Zeichenfolgendaten vermieden wird . Die Implementierung würde die Kopie verschieben, bis Sie c_str aufrufen oder eine der Zeichenfolgen ändern. Es würde niemals eine Kopie gemacht werden, wenn die betreffenden Zeichen nur gelesen würden.

(Copy-on-Write-Implementierungen machen in Multithread-Umgebungen nicht viel Spaß, und die typischen Einsparungen bei Speicher/Zuweisung sind den komplexeren Code heutzutage nicht wert, weshalb sie nur selten durchgeführt werden.).


In ähnlicher Weise ermöglicht string::data Eine andere interne Darstellung, z. ein Seil (verknüpfte Liste von Stringsegmenten). Dies kann die Einfüge-/Ersetzungsvorgänge erheblich verbessern. Auch hier müsste die Liste der Segmente auf ein einzelnes Segment reduziert werden, wenn Sie c_str oder data aufrufen.

3
peterchen

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.

2
Nam Burger

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