8

今天有许多关于关联容器std::weak_ptr和. 有许多帖子指出在 a 中使用a是不正确的,因为如果弱指针过期,它将是未定义的行为。这个对吗?std::owner_lessstd::setstd::mapweak_ptrstd::set

4

1 回答 1

10

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

一、定义std::owner_less

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

    在 , 定义的等价关系下operator()!operator()(a, b) && !operator()(b, a)两个shared_ptrorweak_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().

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

他们在这里要注意的关键是,创建空的唯一方法weak_ptr是默认构造它,或者从以前的空weak_ptr或复制/移动/分配一个shared_ptr。同样重要的是要注意,您不能通过weak_ptr简单地让weak_ptr过期来获得空白。过期的weak_ptr只是use_count零。

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

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

于 2014-04-22T03:55:50.833 回答