[英]Is it safe to use a weak_ptr in a std::set or key of std::map
There have been a number of questions today regarding std::weak_ptr
and std::owner_less
and their use in the associative containers std::set
and std::map
. 今天有很多关于
std::weak_ptr
和std::owner_less
以及它们在关联容器std::set
和std::map
。 There are a number of posts stating that using a weak_ptr
in a std::set
is incorrect, since if the weak pointer expires, it will be Undefined Behavior. 有很多帖子声称在
std::set
中使用weak_ptr
是不正确的,因为如果弱指针到期,它将是Undefined Behavior。 Is this correct? 这个对吗?
One of the reasons std::owner_less
exists is to provide this ordering, and guarantee its safety in the presence of expiring weak pointers. std::owner_less
存在的原因之一是提供这种排序,并在存在即将到期的弱指针时保证其安全性。 My logic is 我的逻辑是
First, the definition of std::owner_less
首先,定义
std::owner_less
operator() defines a strict weak ordering as defined in 25.4
operator()定义了25.4中定义的严格弱排序
under the equivalence relation defined by
operator()
,!operator()(a, b) && !operator()(b, a)
, twoshared_ptr
orweak_ptr
instances are equivalent if and only if they share ownership or are both empty.在
operator()
!operator()(a, b) && !operator()(b, a)
定义的等价关系下,当且仅当它们共享所有权或者都是空的时,两个shared_ptr
或weak_ptr
实例是等效的。
The two cases are 这两个案例是
Now, I believe the confusion is over the second term. 现在,我认为混乱是在第二个任期。 The key is that "empty" in the standard means that the
weak_ptr
does not share ownership with any object. 关键是标准中的“空”意味着
weak_ptr
不与任何对象共享所有权。 Again, the standard states 同样,标准规定
constexpr weak_ptr() noexcept;
Effects: Constructs an empty
weak_ptr
object.效果:构造一个空的
weak_ptr
对象。
Postconditions:use_count() == 0
.后置条件:
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: The second and third constructors shall not participate in the overload resolution unless
Y*
is implicitly convertible toT*
.要求:除非
Y*
可隐式转换为T*
否则第二个和第三个构造函数不应参与重载决策。Effects: If
r
is empty, constructs an emptyweak_ptr
object;效果:如果
r
为空,则构造一个空的weak_ptr
对象; otherwise, constructs aweak_ptr
object that shares ownership withr
and stores a copy of the pointer stored inr
.否则,构造一个与
r
共享所有权的weak_ptr
对象,并存储存储在r
中的指针的副本。Postconditions:
use_count() == r.use_count()
.后置条件:
use_count() == r.use_count()
。
Swap is defined as swapping the states of the two weak_ptr
s, and assignment is defined as using the constructors above along with a swap. Swap定义为交换两个
weak_ptr
的状态,赋值定义为使用上面的构造函数和swap。
They key to note here is that the only way to create an empty weak_ptr
is to default construct it, or copy/move/assign one from a previously empty weak_ptr
or shared_ptr
. 这里需要注意的是,创建空
weak_ptr
的唯一方法是默认构造它,或者从先前为空的weak_ptr
或shared_ptr
复制/移动/分配一个。 It's also important to note that you cannot get an empty weak_ptr
by simply letting the weak_ptr
expire. 同样重要的是要注意,你不能得到一个空
weak_ptr
通过简单地让weak_ptr
到期。 An expired weak_ptr
simply has a use_count
of zero. 过期的
weak_ptr
只有一个use_count
为零。
As a practical matter, when a shared_ptr
is created, a reference count object has to be created, either separate from the data using the shared_ptr
constructor, or in the same memory allocation when std::make_shared
is used. 实际上,当创建
shared_ptr
时,必须创建引用计数对象,或者使用shared_ptr
构造函数与数据分开,或者在使用std::make_shared
时在相同的内存分配中创建引用计数对象。 When a weak_ptr
is constructed from that shared_ptr
, it will point to that same control structure and reference count. 当从该
shared_ptr
构造weak_ptr
,它将指向相同的控制结构和引用计数。 When the shared_ptr
is destroyed, it may destroy the data, but the reference count object has to remain until all of the weak_ptr
that share ownership are removed. 当
shared_ptr
被销毁时,它可能会破坏数据,但引用计数对象必须保留,直到删除共享所有权的所有weak_ptr
。 Otherwise, the weak_ptr
would have a dangling pointer reference. 否则,
weak_ptr
将有一个悬空指针引用。
So, all of this taken together means that it is safe to use std::weak_ptr
as they key of a std::map
or in a std::set
, as long as you use std::owner_less
to perform the ordering. 所以,所有这些结合在一起意味着使用
std::weak_ptr
作为std::map
键或std::set
,只要你使用std::owner_less
来执行排序。 The above guarantees that the ordering of the weak_ptr
will remain the same even if it expires while it's in the container. 上面保证
weak_ptr
的顺序将保持不变,即使它在容器中它到期时也是如此。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.