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

Dav*_*e S 7 c++ weak-ptr c++11

已经有关于一些问题的今天std::weak_ptrstd::owner_less及其关联容器使用std::setstd::map.有很多帖子声明weak_ptr在a 中使用a std::set是不正确的,因为如果弱指针到期,它将是Undefined Behavior.它是否正确?

Dav*_*e S 9

std::owner_less存在的一个原因是提供这种排序,并在存在即将到期的弱指针的情况下保证其安全性.我的逻辑是

一,定义 std::owner_less

  • operator()定义了25.4中定义的严格弱排序

    在由...定义的等价关系下operator(),当且仅当它们共享所有权或者都是空的时!operator()(a, b) && !operator()(b, a),两个shared_ptrweak_ptr实例是等价的.

这两个案例是

  1. 它们共享同一个对象,实际上它们意味着它们共享相同的引用计数对象.
  2. 他们都是空的.

现在,我认为混乱是在第二个任期.关键是标准中的"空"意味着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().

Swap定义为交换两个weak_ptrs 的状态,赋值定义为使用上面的构造函数和swap.

这里要注意的关键是,创建一个空的唯一方法weak_ptr是默认构造它,或者从以前的空weak_ptr或者复制/移动/分配一个shared_ptr.同样重要的是要注意,weak_ptr只要让weak_ptr过期,你就无法获得空洞.过期weak_ptr只有use_count零.

实际上,当shared_ptr创建a时,必须创建引用计数对象,或者使用shared_ptr构造函数与数据分开,或者在std::make_shared使用时使用相同的内存分配.当a weak_ptr由此构造时shared_ptr,它将指向相同的控制结构和引用计数.当shared_ptr销毁时,它可能会破坏数据,但引用计数对象必须保留,直到weak_ptr删除所有共享所有权.否则,weak_ptr将有一个悬空指针引用.

因此,所有这些结合在一起意味着只要您使用它来执行排序,就可以安全地使用std::weak_ptr它们作为a std::map或a的键.上述保证即使它在容器中的到期,它的排序也将保持不变. std::setstd::owner_lessweak_ptr