「EffectiveSTL」のScottMeyerは、使用するデータ構造を決定する際に考慮すべきことの1つは、コンテナーが参照カウントを使用するかどうかであると述べています。彼は、このアプローチにはいくつかの行動異常があると言います。
それらのいくつかは何ですか?'string'や'rope'のようなコンテナが異常な動作をするのはなぜですか?
「EffectiveSTL」のScottMeyerは、使用するデータ構造を決定する際に考慮すべきことの1つは、コンテナーが参照カウントを使用するかどうかであると述べています。彼は、このアプローチにはいくつかの行動異常があると言います。
それらのいくつかは何ですか?'string'や'rope'のようなコンテナが異常な動作をするのはなぜですか?
他の方もおっしゃっていますが、典型的な例はstd::string
. マルチスレッド プログラムでのロックに関するパフォーマンスの問題に加えて、参照カウント文字列にはスレッドレスの問題があります。これを想像してください:
string s = "hello";
string t = s; // s and t share data
char &c = t[0]; // copy made here, since t is non-const
問題は、非 constoperator[]
が共有されている場合、文字列のコピーを作成する必要があることです。これは、返された参照を後で文字列を変更するために使用できるためです (それを非参照に割り当てることはできますが、char
動作operator[]
する必要があるかどうかはわかりません)。異なる)。一方、const operator[]
はコピーを作成しないようにする必要があります。これは、参照カウントのすべての利点を排除するためです (実際には常にコピーを作成することを意味します)。
const char &get_first(const string &s) {
return s[0]; // no copy, s is const
}
string s = "hello";
string t = s; // s and t share data
const char &c1 = get_first(t); // no copy made here
const char &c2 = t[0]; // copy made, since t is non-const
// c1 just got invalidated (in fact, it's pointing at s[0], not t[0]).
s[0] = 'X';
printf("%c, %c\n", c1, c2); // outputs "X, h"
ご覧のとおり、この区別は紛らわしく、予期しない動作を引き起こす可能性があります。
コピー オン ライト セマンティクスとそのパフォーマンスへの影響に関する古い記事を次に示します: http://www.gotw.ca/gotw/045.htm。
std::string
C++ 11標準で参照カウントされないように変更する動機を持つ提案は次のとおりです: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2534.html。これは、上記の例が基づいているものです。
項目 13 で、Meyers はマルチスレッドと refcounted 文字列の問題について詳しく説明しています。
std::string
これは、ロック
の正確な実装と使用パターンに大きく依存します。マルチスレッド環境で明らかに無害な使用が隠しロックのために遅延を引き起こす場合、
それは問題になる可能性があります。std::string
ループ内でのこのようなロックとコンテキスト スイッチのペナルティは、非常に大きくなる可能性があります。ただし、デッドロックが発生することはありません。
問題になる必要はありません。この本は 10 年以上前のものです。その間、スレッドの実装が改善されました。Linux-Futex などは、ほとんどの場合、よりスムーズに動作します。
別のポイント: (Meyers がこれについても議論したかどうかはわかりません...)
refcountedstd::string
は、コピーオンライトのセマンティクスがあることを意味します。それは一般的に良いことです。実際のコピーは、実際に必要になるまで延期されます。しかし、これはまた、おそらく予測が難しい時点でコピーの価格を支払わなければならないことを意味します.
例として、参照カウント文字列、特に「サブパート」処理 (開始/終了スライスを含む) を持つ文字列で発生する可能性のある異常の 1 つは、「不幸なロック」です。
ファイルのテキスト全体にメモリを割り当てるとします。次に、ファイルを解析し、「slice()」、「left()」、「mid()」または同等のメソッドを使用します。ファイルの文字列全体のロックを終了する可能性がありますが、実際には文字列データが含まれているのはごく一部にすぎない可能性があります (残りは既に解析された数字、句読点などです)。したがって、ピーク使用量をより簡単に制御しながら、最終的に必要以上のメモリを使用した可能性があります。この場合、マルチスレッドを使用し、さまざまなスレッドで文字列の一部を集中的に使用すると、2 つ目の問題が発生する可能性があります。不要なメモリ競合、文字列の参照カウントが常にインクリメント/デクリメントされ、アトミック性が int になる可能性があります。道、
ただし、アプリケーションの潜在的な問題を知っていて、それらを防止する限り、参照カウントに反対するものは何もありません (この場合は、単に文字列をコピーして「単独」にします)。
原則として、参照カウントは、競合状態、デッドロック、またはいずれかを回避するための過度の同期など、通常のマルチスレッドの問題の影響を受けます。
次に、通常はクロージャーのような動作を必要とするコンテキストの問題があります。つまり、明らかにスコープ外になった後にオブジェクトをキャプチャする必要がある場合がありますが、これは STL によって回避される可能性があります。私は STL の専門家ではありません。
ここには、スマート ポインターに関連するさまざまなバロック エッジ ケースについて説明するディスカッションがあります。