今日、連想コンテナおよびでのstd::weak_ptrおよびそれらの使用に関して、多くの質問がありました。ウィーク ポインターが期限切れになると未定義の動作になるため、 aで aを使用することは正しくないと述べている投稿が多数あります。これは正しいです?std::owner_lessstd::setstd::mapweak_ptrstd::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_count0 です。
実際問題として、shared_ptrが作成されるとき、コンストラクタを使用してデータとは別に参照カウント オブジェクトを作成するか、 を使用するshared_ptrときに同じメモリ割り当てで作成する必要std::make_sharedがあります。がそのweak_ptrから構築されるとshared_ptr、同じ制御構造と参照カウントを指します。がshared_ptr破棄されると、データが破棄される可能性がありますが、参照カウント オブジェクトは、weak_ptrその共有所有権がすべて削除されるまで保持する必要があります。そうしweak_ptrないと、ダングリング ポインター参照が発生します。
したがって、これらすべてをまとめると、を使用して順序付けを実行する限り、またはstd::weak_ptrのキーとして安全に使用できることを意味します。上記により、will がコンテナ内にある間に有効期限が切れても、 will の順序が同じままであることが保証されます。 std::mapstd::setstd::owner_lessweak_ptr