c_str()
とdata()
(STL およびその他の実装における)の違いは、c_str()
常に null で終了し、そうdata()
ではないといういくつかの場所を読みました。私が実際の実装で見た限り、それらは同じことをするか、またはdata()
呼び出しますc_str()
。
ここで何が欠けていますか?どのシナリオでどちらを使用するのがより正しいですか?
ドキュメントは正しいです。c_str()
null で終了する文字列が必要な場合に使用します。
実装者が心配する必要がないdata()
という点でたまたま実装した場合でも、文字列を null で終了する必要がない場合は引き続き使用します。一部の実装では、c_str() よりも優れたパフォーマンスが得られる場合があります。c_str()
data()
文字列は必ずしも文字データで構成する必要はなく、任意の型の要素で構成できます。そのような場合data()
は、より意味があります。c_str()
私の意見では、文字列の要素が文字ベースの場合にのみ本当に役立ちます。
補足: C++11 以降では、両方の関数が同じである必要があります。つまりdata
、null で終了する必要があります。cppreferenceによると、「返された配列は null で終了します。つまり、data() と c_str() は同じ機能を実行します。」
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
ようなポインタp[0,size()]
。
21.4.5basic_string要素アクセス[string.access]
const_reference operator[](size_type pos) const noexcept;
1必要なもの:pos <= size()。2戻り値:
*(begin() + pos) if pos < size()
、それ以外の場合、値を持つタイプTのオブジェクトへの参照は、参照されたcharT();
値を変更してはなりません。
それらが同じことを行うこと、または .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 つのバッファーを使用することです。null で終了するバッファが 1 つあるということは、std::string を実装するときに常に 1 つの内部バッファだけを使用できることを意味します。
すでに回答されていますが、目的に関するいくつかのメモ: 実装の自由。
std::string
操作 (反復、連結、要素の変更など) では、ゼロ ターミネータは必要ありません。string
ゼロで終了する文字列を期待する関数にを渡さない限り、省略できます。
これにより、実装で部分文字列に実際の文字列データstring::substr
を共有させることができます。共有文字列データへの参照と開始/終了範囲を内部的に保持し、実際の文字列データのコピー (および追加の割り当て) を回避できます。c_str
文字列のいずれかを呼び出すか変更するまで、実装はコピーを延期します。関連する部分文字列が読み取られるだけの場合、コピーは作成されません。
(コピー オン ライトの実装は、マルチスレッド環境ではあまり面白くありません。さらに、典型的なメモリ/割り当ての節約は、今日のより複雑なコードに見合わないため、めったに行われません)。
同様にstring::data
、異なる内部表現、たとえばロープ (文字列セグメントのリンクされたリスト) を許可します。これにより、挿入/置換操作が大幅に改善されます。c_str
ここでも、またはを呼び出すときに、セグメントのリストを 1 つのセグメントに折りたたむ必要がありますdata
。
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.