简体   繁体   English

在std :: set或std :: map的键中使用weak_ptr是否安全

[英]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_ptrstd::owner_less以及它们在关联容器std::setstd::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) , two shared_ptr or weak_ptr instances are equivalent if and only if they share ownership or are both empty. operator() !operator()(a, b) && !operator()(b, a)定义的等价关系下,当且仅当它们共享所有权或者都是空的时,两个shared_ptrweak_ptr实例是等效的。

The two cases are 这两个案例是

  1. They share the same object, which in practical terms means they share the same reference count object. 它们共享同一个对象,实际上它们意味着它们共享相同的引用计数对象。
  2. They are both empty. 他们都是空的。

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 to T* . 要求:除非Y*可隐式转换为T*否则第二个和第三个构造函数不应参与重载决策。

    Effects: If r is empty, constructs an empty weak_ptr object; 效果:如果r为空,则构造一个空的weak_ptr对象; otherwise, constructs a weak_ptr object that shares ownership with r and stores a copy of the pointer stored in r . 否则,构造一个与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_ptrshared_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM