【发布时间】:2014-06-06 06:24:37
【问题描述】:
今天有很多关于std::weak_ptr 和std::owner_less 以及它们在关联容器std::set 和std::map 中的使用的问题。有许多帖子指出在std::set 中使用weak_ptr 是不正确的,因为如果弱指针过期,它将是未定义的行为。这是正确的吗?
【问题讨论】:
今天有很多关于std::weak_ptr 和std::owner_less 以及它们在关联容器std::set 和std::map 中的使用的问题。有许多帖子指出在std::set 中使用weak_ptr 是不正确的,因为如果弱指针过期,它将是未定义的行为。这是正确的吗?
【问题讨论】:
std::owner_less 存在的原因之一是提供这种排序,并在存在过期弱指针的情况下保证其安全性。我的逻辑是
一、std::owner_less的定义
operator() 定义了 25.4 中定义的严格弱排序
在
operator()、!operator()(a, b) && !operator()(b, a)定义的等价关系下,两个shared_ptr或weak_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 为零。
实际上,当创建shared_ptr 时,必须创建一个引用计数对象,或者使用shared_ptr 构造函数与数据分开,或者在使用std::make_shared 时在相同的内存分配中创建。当从shared_ptr 构造weak_ptr 时,它将指向相同的控制结构和引用计数。当shared_ptr 被销毁时,它可能会销毁数据,但引用计数对象必须保留,直到所有共享所有权的weak_ptr 被删除。否则,weak_ptr 将有一个悬空指针引用。
因此,所有这些加在一起意味着使用std::weak_ptr 作为std::map 或std::set 的键是安全的,只要您使用std::owner_less 执行排序。以上保证了weak_ptr 的顺序将保持不变,即使它在容器中过期也是如此。
【讨论】: