今天有许多关于关联容器std::weak_ptr和. 有许多帖子指出在 a 中使用a是不正确的,因为如果弱指针过期,它将是未定义的行为。这个对吗?std::owner_lessstd::setstd::mapweak_ptrstd::set
1 回答
存在的原因之一std::owner_less是提供这种排序,并在存在过期弱指针的情况下保证其安全性。我的逻辑是
一、定义std::owner_less
operator() 定义了 25.4 中定义的严格弱排序
在 , 定义的等价关系下
operator(),!operator()(a, b) && !operator()(b, a)两个shared_ptrorweak_ptr实例是等价的当且仅当它们共享所有权或都是空的。
这两种情况是
- 它们共享同一个对象,这实际上意味着它们共享同一个引用计数对象。
- 他们都是空的。
现在,我相信混乱已经结束了第二个学期。关键是标准中的“空”意味着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;要求:第二个和第三个构造函数不应参与重载决议,除非
Y*隐式转换为T*.效果:如果
r为空,则构造一个空weak_ptr对象;否则,构造一个weak_ptr与 . 共享所有权的对象,r并存储存储在r.后置条件:
use_count() == r.use_count().
交换定义为交换两个weak_ptrs 的状态,赋值定义为使用上面的构造函数和交换。
他们在这里要注意的关键是,创建空的唯一方法weak_ptr是默认构造它,或者从以前的空weak_ptr或复制/移动/分配一个shared_ptr。同样重要的是要注意,您不能通过weak_ptr简单地让weak_ptr过期来获得空白。过期的weak_ptr只是use_count零。
实际上,当创建 a 时shared_ptr,必须创建一个引用计数对象,或者使用shared_ptr构造函数与数据分开,或者在使用时在相同的内存分配std::make_shared中。当weak_ptr从 that 构造a 时shared_ptr,它将指向相同的控制结构和引用计数。当shared_ptr被销毁时,它可能会销毁数据,但引用计数对象必须保留,直到所有weak_ptr共享所有权被删除。否则,weak_ptr将有一个悬空指针引用。
因此,所有这些加在一起意味着只要您用于执行排序,就可以安全地使用std::weak_ptr它们作为 astd::map或 a 的键。以上保证即使它在容器中过期,它的顺序也将保持不变。 std::setstd::owner_lessweak_ptr