7

参照カウントを使用する std::string 実装を検討する場合は、次のシナリオを検討してください。

int main()
{
  string english = "Hello";
  string german  = english; //refcnt = 2
  string german2 = german;

  /* L1 */ german[1] = 'a';
  /* L2 */ *(german2.begin() + 1) = 'A';

  cout << english << endl << german << endl << german2 << endl;
  return 0;
}

L1 と L2 で何が起こるか? 参照カウントが壊れていて、ディープ コピーが実行されていますか? 私はそう思いますが、私の懸念は、それが発生した場合、簡単なことをすることです:

cout << german[1] << endl; 

または単純な:

cout << *(german.begin()) << endl;

const 以外のコンテキストでは、不要なディープ コピーが実行されます。私は正しいですか?実装はこの詳細をどのように処理しますか?

4

2 に答える 2

6

おっしゃるとおり、4 つの例 (L1、L2、および以下の 2 つ) のすべてでコピーが作成されますが、後者の 2 つの場合は不要です。

残念ながら、operator[] の非 const バージョンが呼び出されるか、非 const イテレーターが逆参照される場合、結果の非 const 参照がオブジェクトの変更に使用されるかどうかを実装が判断する方法がないため、安全にプレイしてコピーを作成する必要があります。

C++11は、非 const オブジェクトで呼び出された場合でも const イテレータを返す文字列およびその他のコンテナーに関数cbegin()およびを追加しました。cend()これにより、問題が軽減されます。operator[] に匹敵するソリューションを知りません。

注: operator[] またはイテレータの operator*() がプロキシ型を返すようにすることは、他の回答者の一部が示唆しているように、コンテナーの要件を破るため、実際にはオプションではありません。その 1 つは、これらの関数が実際の参照を返すことです。vector<bool>(これが、これが間違いであることに誰もが同意する理由です。この方法でプロキシを使用しています)。

(もちろん、独自の参照カウント クラスを作成している場合は、これを実現するためにプロキシ型を使用することを妨げるものは何もありません。)

于 2012-06-21T23:59:23.043 に答える
2

これを実現する 1 つの方法は、プロキシ クラスを使用することです。そのため、char を取得する代わりに文字列にインデックスを付けると、char のように見えるオブジェクトが取得されます。書き込みが実行されると、元の文字列にディープ コピーが発生します。

于 2012-06-21T23:59:19.510 に答える