5
#include <string>
#include <iostream>

int main() {
    std::string s = "abcdef";

    std::string s2 = s;

    auto begin = const_cast<std::string const &>(s2).begin();
    auto end = s2.end();

    std::cout << end - begin << '\n';
}

begin() constこのコードは、 の結果と の結果を混合しend()ます。これらの関数のいずれも、反復子を無効にすることは許可されていません。end()ただし、イテレータ変数を無効にしないという要件がbegin実際に変数beginが で使用できることを意味するかどうかは興味がありますend

C++98 のコピー オン ライト実装を考えてみましょうstd::string。これらの関数の結果を使用して文字列を変更できるため、const 以外の関数begin()と関数によって内部バッファーがコピーされます。end()したがって、begin上記は最初は と の両方で有効ですss2、非 const メンバーを使用すると、それを生成したコンテナーであるend()に対して有効ではなくなります。s2

上記のコードは、libstdc++ などのコピーオンライト実装で「予期しない」結果を生成します。end - beginと同じではなくs2.size()、libstdc++は別の数値を生成します。

  • begin有効なイテレータをs2、それが取得されたコンテナであるから無効にすることは、イテレータを「無効にする」ことになりますか? .end()イテレータの要件を見ると、 が呼び出された後、このイテレータに対してすべての要件が満たされているように見えるためbegin、有効なイテレータとしての資格があり、無効化されていない可能性があります。

  • 上記のコードは C++98 で適切に定義されていますか? C++11 で、コピー オン ライトの実装を禁止しているのはどれですか?

私自身が仕様を簡単に読んだところ、仕様が不十分であると思われるため、 const バージョンと非 const バージョンを混在させなくても、 と の結果を一緒に使用できるbegin()という保証はありません。end()

4

4 に答える 4

6

おっしゃるとおり、C++11 はこの点で以前のバージョンとは異なります。コピー オン ライトを許可する試みはすべて削除されたため、C++11 では問題ありません。C++11 より前のコードでは、未定義の動作が発生します。呼び出しs2.end()は、既存のイテレータを無効にすることができます (g++ ではそうでしたし、今でもそうかもしれません)。

s2コピーではない場合でも、標準ではイテレータを無効にすることが許可されていることに注意してください。実際、C++98 の CD は、未定義の動作のようなものさえ作成しましf( s.begin(), s.end() )s[i] == s[j]。これは土壇場で初めて認識され、begin()end()またはへの最初の呼び出しのみ[]がイテレータを無効にできるように修正されました。

于 2015-02-26T17:19:09.857 に答える
2

コードは問題ありません。CoW 実装は、イテレータに危険がある場合、または要素への参照が保持されている場合に共有を解除する必要があります。つまり、1 つの文字列内の要素にアクセスする何かがあり、そのコピーが同じことを試みる場合、つまり反復子または添え字演算子を使用する場合、共有を解除する必要があります。イテレータを認識し、必要に応じて更新できます。

もちろん、並行システムではデータ競合なしでこれらすべてを行うことはほとんど不可能ですが、C++11 より前ではデータ競合はありません。

于 2015-02-26T17:12:40.617 に答える
2

N3337 (これは本質的に C++11 と同じです) の時点で、仕様は ([string.require]/4) を読み取ります。

basic_string シーケンスの要素を参照する参照、ポインター、および反復子は、その basic_string オブジェクトを次のように使用すると無効になる場合があります。
[...]
- operator[]、at、front、back、およびbegin、rbegin、end、および rend です。

少なくとも私が読んだように、これは、への呼び出しbeginまたはendイテレータを無効にすることは許可されていないことを意味します。直接は述べていませんが、これは、constメンバー関数への呼び出しがイテレーターを無効にできないという意味でもあります。

この文言は、少なくとも n4296 まで同じままです。

于 2015-02-26T17:12:56.077 に答える