今天有很多关于std::weak_ptr
和std::owner_less
及其在关联容器std::set
和std::map
中使用的问题。有很多帖子指出在weak_ptr
中使用std::set
是不正确的,因为如果弱指针到期,则它将是未定义的行为。这是对的吗?
答案 0 :(得分:9)
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_ptr
的状态,并且赋值被定义为使用上面的构造函数和交换。
他们需要注意的是,创建空weak_ptr
的唯一方法是默认构建它,或者从以前为空的weak_ptr
或shared_ptr
复制/移动/分配一个。同样重要的是要注意,只需让weak_ptr
过期就无法获得空weak_ptr
。已过期的weak_ptr
只有use_count
为零。
实际上,当创建shared_ptr
时,必须创建引用计数对象,或者使用shared_ptr
构造函数与数据分开,或者在{{std::make_shared
时创建相同的内存分配1}}被使用。当weak_ptr
由shared_ptr
构造时,它将指向相同的控制结构和引用计数。当shared_ptr
被销毁时,它可能会破坏数据,但必须保留引用计数对象,直到删除共享所有权的所有weak_ptr
为止。否则,weak_ptr
将有一个悬空指针引用。
所以,所有这些结合在一起意味着只要您使用std::weak_ptr
就可以安全地使用std::map
作为std::set
或std::owner_less
的关键字执行排序。以上保证weak_ptr
的排序即使在容器中过期时也会保持不变。