5

std::shared_ptr の作成またはコピーには、いくつかのオーバーヘッド (参照カウンターのアトミック インクリメントなど) が含まれることを読みました。

しかし、代わりにそれから std::weak_ptr を作成するのはどうですか:

Obj * obj = new Obj();
// fast
Obj * o = obj;
// slow
std::shared_ptr<Obj> a(o);
// slow
std::shared_ptr<Obj> b(a);
// slow ?
std::weak_ptr<Obj> c(b);

パフォーマンスが向上することを期待していましたが、共有ポインターがまだ弱い参照カウンターをインクリメントする必要があることはわかっています..だから、これはまだshared_ptrを別のものにコピーするのと同じくらい遅いですか?

4

2 に答える 2

12

以前のプロジェクトで使用された 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をコピーする代わりに移動する機会がある場合は、移動するためにいくつかの余分な文字を入力するのに苦労する価値があることを理解できるように指摘します。

于 2013-11-29T19:00:46.770 に答える