最近、C++ 11から始めました。 _weak_ptr
_について勉強しました。生のポインタを取得する方法は2つあります。
lock()
関数
_shared_ptr<Foo> spFoo = wpPtr.lock();
if(spFoo) {
spFoo->DoSomething();
}
_
expired()
関数
_if(!wpPtr.expired())
{
shared_ptr<Foo> spFoo = wpPtr.lock();
spFoo->DoSomething();
}
_
どちらが良い方法ですか? 2つの方法の違いは何ですか?
したがって、共有ptrとweak ptrはスレッドセーフであり、特定のスレッドにローカルなオブジェクトのインスタンスがあり、それらが共通のポイントされたオブジェクトを共有している場合、あるスレッドと別のスレッドでそれらと対話でき、すべてが機能します。
これが正しく機能するためには、それらを適切に使用する必要があります。
wp.expired()
は、「期限切れの弱いptrをすべてバッファから削除する」などの場合にのみ役立ちます。それはあなたがそれを置く目的には役に立ちません。
すべての弱いポインタは、一度期限切れになると、期限切れのままになります。ただし、エンゲージされた弱いポインタは、エンゲージされていることを確認した後、すぐに期限切れになる可能性があります。
_if(!wpPtr.expired()) {
// <<--- here
shared_ptr<Foo> spFoo = wpPtr.lock();
spFoo->DoSomething();
}
_
_<<--- here
_では、マルチスレッド環境でのwpPtr
の状態についてnothingがわかります。有効期限が切れている場合とそうでない場合があります。一方:
_if(wpPtr.expired()) {
// <<--- there
}
_
_<<--- there
_で、私たちはdo弱いポインタが期限切れになっていることを知っています。
File ioや他の種類の「トランザクション」操作と同様に、何かができるかどうかを確認する唯一の方法はやってみてくださいです。実行できるはずだと判断してから実行するまでの間に、状態が変化して操作が失敗する可能性があります。
ほぼ確実にできなかった早い段階で解決できる場合があります。これは便利な場合もありますが、試してみるまで実行できるかどうかはわかりません。試行は失敗する可能性があり、その時点でエラーを処理します。
_if(auto spFoo = wpPtr.lock()) {
spFoo->DoSomething();
}
_
これは、弱いポインタと対話するための「正しい」方法です。弱いポインターの有効性をテストし、同じ操作で共有ポインターを取得します。
if()
ヘッダーの外側にspFoo
を作成することは許容されますが、spFoo
のスコープは有効なゾーンに正確に制限されるため、この手法をお勧めします。
他の好ましい手法は、SFINAEに適したコードを記述した早期終了です。
_auto spFoo = wpPtr.lock();
if(!spFoo) return error("wp empty");
spFoo->DoSomething();
_
これにより、コードフローの「予想される」実行が、インデント、条件、またはジャンプなしでフラットラインになります。
2番目のバリアントには2つの問題があります。
wpPtr.expired()
spFoo
を逆参照する前に必要なチェックif (spFoo)
がありません。最初のバリアントはトランザクション型であり、最終的にウィークポインターによって参照されるオブジェクトを操作する必要がある場合に使用します。
オプション1。
オプション2を選択した場合、wpPtr.expired()
の呼び出しとwpPtr.lock()
の呼び出しの間に_weak_ptr
_の有効期限が切れている可能性があり、行spFoo->DoSomething()
はnullを逆参照しようとします。 _shared_ptr
_。
以下は、_weak_ptr
_に関連する操作です。アプローチ2はスレッドセーフではないため、オプション1を使用する必要があります。
w.use_count()
w
と所有権を共有する_shared_ptr
_の数
w.expired()
は、w.use_count()
がゼロの場合はtrue
を返し、それ以外の場合はfalse
を返します。
w.lock()
expired
がtrue
の場合、nullを返します_shared_ptr
_;それ以外の場合は、w
が指すオブジェクトに_shared_ptr
_を返します。
(2)スレッドセーフではありません
_// let p be the last shared_ptr pointing at the same object as wpPtr
if (!wpPtr.expired())
{
// we enter the if-statement because wpPtr.use_count() is 1
// p goes out of scope on its thread, the object gets deleted
shared_ptr<Foo> spFoo = wpPtr.lock(); // null shared_ptr
spFoo->DoSomething(); // ERROR! deferencing null pointer
}
_
(1)スレッドセーフ
_// let p be the last shared_ptr pointing at the same object as wpPtr
shared_ptr<Foo> spFoo = wpPtr.lock();
// now, wpPtr.use_count() is 2, because spFoo and p are both pointing at the object
// p goes out of scope on its thread, but spFoo is still pointing at the object
if(spFoo) {
spFoo->DoSomething(); // OK! safe to dereference
}
_
cppreference.com から引用するには:
std::weak::lock
は効果的に
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
基になるオブジェクトが有効かどうかを確認するためにexpiredを使用し、オブジェクトをstd::shared_ptr
にプロモートする可能性があるようにロックします