以前のプロジェクトで使用された shared/weak_ptr システムに関するAlec の非常に興味深い説明に加えて、典型的なstd::shared_ptr/weak_ptr
実装で何が起こる可能性があるかについてもう少し詳しく説明したいと思います。
// slow
std::shared_ptr<Obj> a(o);
上記の構成の主なコストは、2 つの参照カウントを保持するためにメモリのブロックを割り当てることです。ここでは、アトミック操作を行う必要はありません (実装が の下で行うかどうかは別としてoperator new
)。
// slow
std::shared_ptr<Obj> b(a);
コピーの構築における主な費用は、通常、単一のアトミック インクリメントです。
// slow ?
std::weak_ptr<Obj> c(b);
このweak_ptr
コンストラクターの主なコストは、通常、単一のアトミック インクリメントです。このコンストラクターのパフォーマンスは、shared_ptr
コピー コンストラクターのパフォーマンスとほぼ同じになると思います。
注意すべき他の 2 つの重要なコンストラクターは次のとおりです。
std::shared_ptr<Obj> d(std::move(a)); // shared_ptr(shared_ptr&&);
std::weak_ptr<Obj> e(std::move( c )); // weak_ptr(weak_ptr&&);
(そして、移動代入演算子も一致します)
移動コンストラクターは、アトミック操作をまったく必要としません。rhs から lhs に参照カウントをコピーし、rhs == nullptr にします。
移動代入演算子は、代入の前に lhs != nullptr の場合にのみアトミック デクリメントを必要とします。ほとんどの時間 (たとえば a 内vector<shared_ptr<T>>
) は、移動割り当ての前に lhs == nullptr であるため、アトミック操作はまったくありません。
後者 (weak_ptr
移動メンバー) は実際には C++11 ではありませんが、LWG 2315によって処理されています。ただし、ほとんどの実装で既に実装されていると思います ( libc++で既に実装されていることはわかっています)。
これらの move メンバーは、コンテナー内 (例: の下) でスマート ポインターをスクートするときに使用されvector<shared_ptr<T>>::insert/erase
、スマート ポインター コピー メンバーの使用と比較して、測定可能なプラスの影響を与えることができます。
shared_ptr/weak_ptr
をコピーする代わりに移動する機会がある場合は、移動するためにいくつかの余分な文字を入力するのに苦労する価値があることを理解できるように指摘します。