【问题标题】:Is it safe to use a weak_ptr in a std::set or key of std::map在 std::set 或 std::map 的键中使用 weak_ptr 是否安全
【发布时间】:2014-06-06 06:24:37
【问题描述】:

今天有很多关于std::weak_ptrstd::owner_less 以及它们在关联容器std::setstd::map 中的使用的问题。有许多帖子指出在std::set 中使用weak_ptr 是不正确的,因为如果弱指针过期,它将是未定义的行为。这是正确的吗?

【问题讨论】:

    标签: c++ c++11 weak-ptr


    【解决方案1】:

    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()

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

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

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

    因此,所有这些加在一起意味着使用std::weak_ptr 作为std::mapstd::set 的键是安全的,只要您使用std::owner_less 执行排序。以上保证了weak_ptr 的顺序将保持不变,即使它在容器中过期也是如此。

    【讨论】:

    • 你能在这个答案中添加一个结论吗? :)
    • @Drax:当然。我在深夜写了这篇文章,我错过了这样的小细节。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 2023-03-17
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-06
    相关资源
    最近更新 更多