今日、連想コンテナおよびでのstd::weak_ptr
およびそれらの使用に関して、多くの質問がありました。ウィーク ポインターが期限切れになると未定義の動作になるため、 aで aを使用することは正しくないと述べている投稿が多数あります。これは正しいです?std::owner_less
std::set
std::map
weak_ptr
std::set
1 に答える
存在する理由の 1 つは、std::owner_less
この順序付けを提供し、期限切れのウィーク ポインターが存在する場合の安全性を保証することです。私の論理は
まず、定義はstd::owner_less
operator() は、25.4 で定義されている厳密な弱い順序付けを定義します
、 によって定義された同値関係の下で
operator()
、!operator()(a, b) && !operator()(b, a)
2 つshared_ptr
またはweak_ptr
インスタンスは、それらが所有権を共有するか、両方が空である場合にのみ、同等です。
二つのケースは
- これらは同じオブジェクトを共有します。これは、実際には、同じ参照カウント オブジェクトを共有することを意味します。
- どちらも空です。
さて、混乱は第2期以降だと思います。重要なのは、標準の「空」は、weak_ptr
がどのオブジェクトとも所有権を共有しないことを意味するということです。繰り返しますが、標準状態
constexpr weak_ptr() noexcept;
効果: 空の
weak_ptr
オブジェクトを構築します。
事後条件:use_count() == 0
.weak_ptr(const weak_ptr& r) noexcept;
template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept;
template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;
Requires: 2 番目と 3 番目のコンストラクターは、
Y*
暗黙的に に変換可能でない限り、オーバーロードの解決に参加してはなりませんT*
。効果:
r
が空の場合、空のweak_ptr
オブジェクトを構築します。weak_ptr
それ以外の場合は、 と所有権を共有するオブジェクトを構築し、r
に格納されているポインタのコピーを格納しr
ます。事後条件:
use_count() == r.use_count()
.
スワップは 2 つweak_ptr
の の状態を交換することとして定義され、代入は上記のコンストラクターをスワップと共に使用することとして定義されます。
ここで注意すべき重要な点は、空を作成する唯一の方法は、weak_ptr
それをデフォルトで作成するか、以前の空のweak_ptr
またはからコピー/移動/割り当てることshared_ptr
です。weak_ptr
また、単にweak_ptr
期限切れにするだけでは空にできないことに注意することも重要です。期限切れのweak_ptr
は単にuse_count
0 です。
実際問題として、shared_ptr
が作成されるとき、コンストラクタを使用してデータとは別に参照カウント オブジェクトを作成するか、 を使用するshared_ptr
ときに同じメモリ割り当てで作成する必要std::make_shared
があります。がそのweak_ptr
から構築されるとshared_ptr
、同じ制御構造と参照カウントを指します。がshared_ptr
破棄されると、データが破棄される可能性がありますが、参照カウント オブジェクトは、weak_ptr
その共有所有権がすべて削除されるまで保持する必要があります。そうしweak_ptr
ないと、ダングリング ポインター参照が発生します。
したがって、これらすべてをまとめると、を使用して順序付けを実行する限り、またはstd::weak_ptr
のキーとして安全に使用できることを意味します。上記により、will がコンテナ内にある間に有効期限が切れても、 will の順序が同じままであることが保証されます。 std::map
std::set
std::owner_less
weak_ptr