今天有许多关于关联容器std::weak_ptr
和. 有许多帖子指出在 a 中使用a是不正确的,因为如果弱指针过期,它将是未定义的行为。这个对吗?std::owner_less
std::set
std::map
weak_ptr
std::set
1 回答
存在的原因之一std::owner_less
是提供这种排序,并在存在过期弱指针的情况下保证其安全性。我的逻辑是
一、定义std::owner_less
operator() 定义了 25.4 中定义的严格弱排序
在 , 定义的等价关系下
operator()
,!operator()(a, b) && !operator()(b, a)
两个shared_ptr
orweak_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_ptr
s 的状态,赋值定义为使用上面的构造函数和交换。
他们在这里要注意的关键是,创建空的唯一方法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::set
std::owner_less
weak_ptr