web-dev-qa-db-ja.com

文字列c_str()vs. data()

c_str()data()(STLおよびその他の実装)の違いは、c_str()data()は違います。実際の実装で見た限り、それらは同じことを行うか、data()c_str()を呼び出します。

ここで何が欠けていますか?どのシナリオでどちらを使用するのが適切ですか?

92
leon

ドキュメントは正しいです。 nullで終わる文字列が必要な場合は、 c_str() を使用します。

実装者がたまたま data()c_str()に関して実装している場合、心配する必要はありませんが、必要なければdata()を使用してください。 nullで終了する文字列。実装によっては、c_str()よりもパフォーマンスが向上する場合があります。

文字列は必ずしも文字データで構成されている必要はなく、任意のタイプの要素で構成できます。そのような場合、data()の方が意味があります。私の意見では、c_str()は、文字列の要素が文字ベースである場合にのみ本当に役立ちます。

Extra:C++ 11以降では、両方の関数が同じである必要があります。つまり、dataはnullで終了する必要があります。 cppreference :「返された配列はnullで終了しています。つまり、data()とc_str()は同じ機能を実行します。」

99
Scott Langham

C++ 11/C++ 0x で、data()c_str()の違いはなくなりました。したがって、data()の最後にもヌル終端が必要です。

21.4.7.1 _basic_string_アクセサー[string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1戻り値:p + i == &operator[](i)の各iに対して[0,size()]になるようなポインターp。


21.4.5 basic_string要素のアクセス[string.access]

const_reference operator[](size_type pos) const noexcept;

1必須:pos <= size()。 2戻り値:*(begin() + pos) if pos < size()、それ以外の場合、値charT();を持つT型のオブジェクトへの参照は、参照される値は変更されません。

26
mfazekas

同じことをしていること、または.data()が.c_str()を呼び出すことを知っている場合でも、これが他のコンパイラの場合に当てはまると仮定するのは正しくありません。コンパイラが将来のリリースで変更される可能性もあります。

std :: string:を使用する2つの理由

std :: stringは、テキストと任意のバイナリデータの両方に使用できます。

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

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

例1として文字列を使用する場合は、.c_str()メソッドを使用する必要があります。

例2のように文字列を使用する場合は、.data()メソッドを使用する必要があります。これらの場合に.c_str()を使用するのは危険ではなく、レビューのためにバイナリデータを使用することがより明確であるためですあなたのコード。

.data()を使用した場合の落とし穴

次のコードは間違っており、プログラムでセグメンテーション違反を引き起こす可能性があります。

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

実装者が.data()と.c_str()に同じことをさせるのはなぜ一般的なのですか?

こうするほうが効率的だからです。 .data()がnullで終了しないものを返すようにする唯一の方法は、.c_str()または.data()に内部バッファーをコピーさせるか、単に2つのバッファーを使用することです。単一のヌル終了バッファがあるということは、std :: stringを実装するときに常に1つの内部バッファのみを使用できることを意味します。

18
Brian R. Bondy

目的に関するいくつかのメモ:実装の自由。

std::string操作-例反復、連結、要素の突然変異-ゼロターミネータは不要です。 stringをゼロで終了する文字列が必要な関数に渡さない限り、省略できます。

これにより、実装でサブストリングに実際のストリングデータを共有させることができます。string::substrは、共有ストリングデータへの参照と開始/終了範囲を内部的に保持し、実際のストリングデータのコピー(および追加の割り当て)を回避できます実装は、c_strを呼び出すか、文字列を変更するまでコピーを延期します。関係するストライグが読み取られた場合、コピーは作成されません。

(コピーオンライトの実装は、マルチスレッド環境ではあまり楽しくありません。また、一般的なメモリ/割り当ての節約は、今日のより複雑なコードの価値がないため、めったに行われません)。


同様に、string::dataは異なる内部表現を許可します。ロープ(文字列セグメントのリンクリスト)。これにより、挿入/置換操作を大幅に改善できます。ここでも、c_strまたはdataを呼び出すと、セグメントのリストを単一のセグメントにまとめる必要があります。

3
peterchen

前のコメントはすべて一貫していますが、c ++ 17以降では、str.data()がconst char *ではなくchar *を返すことも追加したいと思います

2
Nam Burger

ANSI ISO IEC 14882 2003からの引用(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