文字列c_str()とdata()


102

c_str()data()(STLと他の実装での)の違いは、c_str()常にnullで終了するが、そうdata()でない場合があることをいくつか読んだことがあります。私が実際の実装で見た限りでは、それらは同じことをするか、data()呼び出しますc_str()

ここで何が欠けていますか?どのシナリオで使用する方が正しいですか?

回答:


105

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

実装者data()c_str()あなたの観点から実装することになった場合、心配するdata()必要はありません。文字列をnullで終了する必要がない場合でも使用します。実装によっては、c_str()よりもパフォーマンスが優れている場合があります。

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

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


4
補足2:C ++ 17以降では、の非定数オーバーロード.data()も存在するため、非定数文字列と同等ではなくなりました。
Deduplicator

29

では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)それぞれのiinのようなポインタp [0,size()]


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

const_reference operator[](size_type pos) const noexcept;

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


文字列が文字以外のデータで構成されている場合はどうなりますか。これには、nullを含む文字列データAFAIKで有効です。
taz 2013

3
@tazバイナリデータを格納する場合でも、C ++ 11では、末尾にstd::string追加のメモリを割り当てる必要があります。あなたが行う場合は、両方と0に評価することが保証されているchar'\0'std::string s("\0");s.data()[0]s.data()[1]
bcrist

19

それらが同じように動作すること、または.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()を使用した場合の潜在的な落とし穴

次のコードは誤りであり、プログラムでsegfaultを引き起こす可能性があります。

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つのバッファーを使用することです。単一のnullで終了するバッファがあることは、std :: stringを実装するときに常に1つの内部バッファしか使用できないことを意味します。


6
実際、.data()のポイントは、内部バッファをコピーしないことです。これは、実装が必要になるまで\ 0でcharを無駄にする必要がないことを意味します。2つのバッファが必要になることは決してありません。.c_str()を呼び出す場合は、バッファに\ 0を追加してください。.data()は引き続きそのバッファを返すことができます。
MSalters 2008年

2
2つのバッファを使用するのはばかげていると完全に合意しています。.dataが意図されていた理由は何ですか。
ブライアンR.ボンディ

@ BrianR.Bondy私はこのコードを試しました:.. auto str = string {"Test \ 0String!" }; cout << "DATA:" << str.data()<< endl; 出力は「テスト」であり、文字列全体ではありません。何が問題でしたか?
プログラマー、

最後の部分は間違っています。データとc_strは、0で終了せずに同じバッファを使用する可能性があります。c_strは、最初の呼び出しで単に0を追加できます。
モニカを思い出す

ヘッドアップ、c ++ 11は.data()を.c_str()のエイリアスにしました
hanshenrik

3

それはすでに答えられています、目的に関するいくつかの注記:実装の自由。

std::string操作(反復、連結、要素の変更など)では、ゼロターミネータは必要ありません。あなたが合格しない限りstringゼロで終了する文字列を期待する関数に、それは省略できます。

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

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


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


2

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

これまでのコメントはすべて一貫性がありますが、c ++ 17からstr.data()がconst char *ではなくchar *を返すことも追加したいと思います。


1
constnon-constオーバーロードの両方がC ++ 17以降で使用可能です。
Gupta
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.