7

変更可能な文字への参照を返すのに、 const charへのポインターを返すstd::string::dataのはなぜですか?std::string::c_str()std::string::operator[]

std::string string("eightfold is the greatest");

auto s = string.data();
*s = 'r'; // illegal

auto t = &string[0];
*t = 'r'; // totally fine

auto& c = string[0];
c = 'r'; // totally fine

なぜ返さないstd::string::data()のですか、またはなぜ返さないのですか?std::string::c_str()char*std::string::operator[]char const&

この背後にある理論的根拠は何ですか?

4

2 に答える 2

14

operator []オブジェクトの制御されたシーケンスに直接アクセスできstd::stringます。c_str()もともとしていません。

格納されたシーケンスの元の仕様でstd::stringは、ゼロで終わる文字列である必要はありませんでした。これは、通常c_str()、格納されたシーケンスへの直接ポインタを返すことができないことを意味していました。完全に独立した、個別に割り当てられた、制御されたシーケンスの一時コピーへのポインターを返す必要がありました (ゼロ ターミネーター文字が追加されています)。このため、 によって返された C 文字列を変更しようとしてc_str()もまったく意味がありませんでした。その別の C 文字列に適用された変更は、実際の制御シーケンスには反映されません。(実際、仕様は変更の試みを明示的に禁止していました。たとえば、空std::stringの場合、実装は単に文字列リテラルへのポインターを返すことができます。""、これはもちろん変更不可能で、すべてのオブジェクト間で簡単に共有できましstd::stringた。) したがって、c_str()を返すようにすることは完全に理にかなっていconst char *ます。

C++11 ではc_str()、実際に制御されるシーケンスへの直接ポインターを返すようにする内部仕様が変更されました。ただし、 の外部仕様c_str()は変更されず、従来の仕様との整合性を維持しています。

于 2013-11-03T19:58:25.497 に答える
3

歴史的な理由から、C++ とその標準ライブラリは C 文字列 (文字配列) をサポートしており、多くの C++ コードは入力と出力に C 文字列を使用しています。

データを文字配列に保持する std::string の可能な実装を想像することもできます。これは通常、完全にプライベートな実装の詳細であり、クラスのパブリック インターフェイスを通じて公開されません。

編集: 明示的に言うと、クラスは通常、そのプライベート データの非 const ビューを公開しません。これが問題になる理由を理解するには、次のコードを想像してください。

std::string s("abc");  
char* ps = s.c_str();  //  ps[0] == 'a' and ps[3] == '\0'
ps[3] = 'd';  // string is not null terminated
printf("%s", s.c_str());  // printing non-terminated string.

このような変更により、クラスのユーザーは、不変条件、つまり次の不変条件を破る方法でプライベート データを変更できるようになります。

の契約の一部はoperator[]、呼び出し元が文字列の長さ以上の引数を提供してはならないということです。at(size_t pos)メンバー関数は、例外をスローして境界チェックを強制します。はstd::string::operator[]引き続き安全に使用できません、 のようなポインター逆参照演算子とは異なり、少なくともcontractを文書化ps[3]することは可能です。

編集の終わり

ただし、const char*C 文字列を予期する関数との相互運用性をサポートするために、std::stringはこの文字バッファーを公開します。

もちろん、 と同様にstd::vector、ユーザーは文字列内の個々の要素 (文字) を変更したい場合があります。これが、文字列が を提供する理由operator[]です。

(実際には、string実装には多くの場合、内部に保持する固定長の文字バッファーがあり、文字列の内容がその固定長を超えた場合にヒープに「再割り当て」されます。これは「小さな文字列の最適化」と呼ばれます)。

data()完全にサービス可能なメンバー関数があるのに、なぜメンバー関数があるのc_str()でしょうか? std::arrayこれはジェネリック プログラミングを単純化するためにあると思います。 メンバー関数std::vectorもあり、 s はコンテナーのように動作するように設計されています。data()std::string

于 2013-11-03T19:49:17.180 に答える