web-dev-qa-db-ja.com

string :: c_str()はC ++ 11でnull終了ではなくなりましたか?

C++ 11では、_basic_string::c_str_は_basic_string::data_とまったく同じであると定義され、*(begin() + n)および*(&*begin() + n)とまったく同じであると定義されています。 (0 <= n < size()の場合)。

文字列の末尾に常にnull文字が必要なものは見つかりません。

これは、c_str()がnullで終了する文字列を生成することが保証されなくなったことを意味しますか?

72
Mankarse

文字列は、内部的にnullで終了するバッファを使用する必要があります。 _operator[]_(21.4.5)の定義を見てください。

必須:pos <= size()

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

_c_str_(21.4.7.1/1)を振り返ると、それが_operator[]_で定義されていることがわかります。

戻り値:ポインタpp + i == &operator[](i) for i in [0,size()]

また、_c_str_とdataの両方がO(1)である必要があるため、実装は事実上、nullで終了するバッファを使用する必要があります。

さらに、コメントで DavidRodríguez-dribeas が指摘しているように、戻り値の要件は、&operator[](0)c_str()の同義語として使用できることも意味します。終端のnull文字は同じバッファになければなりません(*(p + size())charT()と等しい必要があるため)。これは、ターミネーターが遅延して初期化された場合でも、中間状態でバッファーを監視することができないことを意味します。

80

実際、新しい規格では.data()と.c_str()が同義語であることを規定していることは事実です。ただし、.c_str()がゼロで終了していないことは示されていません:)

これは、.data()もゼロで終了することに依存できるようになったことを意味します。

ペーパーN2668では、std :: basic_stringのc_str()およびdata()メンバーを次のように定義しています。

_ const charT* c_str() const; 
 const charT* data() const; 
_

戻り値:長さsize()+ 1の配列の最初の要素へのポインタ。最初のsize()要素は* thisで制御される文字列の対応する要素に等しく、最後の要素はcharT()で指定されたnull文字です。

必要:プログラムは、文字配列に格納されている値を変更してはなりません。

これは[〜#〜]ではない[〜#〜] [〜#〜]を意味することに注意してください。std:: stringは、埋め込まれたnull。constchar *として直接使用すると、C文字列が途中で終了します。

補遺:

私は実際に公開された C++ 11の最終仕様 にアクセスできませんが、実際には、仕様の改訂履歴のどこかに文言が削除されているようです。 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

§21.4.7 basic_string文字列演算_[string.ops]_

§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。
  2. 複雑さ:一定の時間。
  3. 必要:プログラムは、文字配列に格納されている値を変更してはなりません。
23
sehe

「歴史」は、誰もがシングルスレッドで作業していたとき、または少なくともスレッドが独自のデータを持つワーカーであったとき、C++の文字列クラスを設計して、文字列の処理を以前よりも簡単にし、オーバーロードしたというものでした。文字列を連結する演算子+。

問題は、ユーザーが次のようなことをすることでした。

_s = s1 + s2 + s3 + s4;
_

そして、それぞれの連結は、文字列を実装しなければならない一時を作成します。

したがって、誰かが「怠惰な評価」の頭脳を持ち、内部で何らかの種類の「ロープ」をすべての文字列とともに格納して、内部表現を連続したバッファに変更するC文字列として誰かがそれを読みたいと思うまで、 。

これにより、上記の問題は解決しましたが、特にマルチスレッドの世界では、.c_str()操作が読み取り専用であることが予期され、何も変更されないため、何もロックする必要がないため、他の問題が発生しました。誰かがマルチスレッドで実行している場合に備えて(スレッド化標準すらなかった場合に備えて)、クラス実装で時期尚早の内部ロックを行うことも良い考えではありませんでした。実際、毎回単純にバッファをコピーするよりも、これを実行する方がコストがかかりました。同じ理由で、「コピーオンライト」実装が文字列実装で放棄されました。

したがって、.c_str()を真に不変の操作にすることは、実行するのが最も賢明なことであることが判明しましたが、現在スレッド対応の標準でこれに「依存」できますか?したがって、新しい標準では、できることを明確に示すことを決定したため、内部表現はnullターミネーターを保持する必要があります。

10
CashCow

よく見つかりました。これは確かに最近採用された規格の欠陥です。現在c_strを使用しているすべてのコードを壊す意図はなかったと思います。私は欠陥レポートを提案するか、少なくともcomp.std.c++で質問することをお勧めします(欠陥に関係する場合、通常は委員会の前で終了します)。

2
James Kanze