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

时间:2014-04-22 03:55:51

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

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

1 个答案:

答案 0 :(得分:9)

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

首先,std::owner_less

的定义
  
      
  • operator()定义了25.4

    中定义的严格弱排序      

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

  •   

这两个案例是

  1. 它们共享同一个对象,实际上意味着它们共享相同的引用计数对象。
  2. 他们都是空的。
  3. 现在,我认为混乱是在第二个任期。关键是"空"在标准中意味着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_ptr的状态,并且赋值被定义为使用上面的构造函数和交换。

    他们需要注意的是,创建空weak_ptr的唯一方法是默认构建它,或者从以前为空的weak_ptrshared_ptr复制/移动/分配一个。同样重要的是要注意,只需让weak_ptr过期就无法获得空weak_ptr。已过期的weak_ptr只有use_count为零。

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

    所以,所有这些结合在一起意味着只要您使用std::weak_ptr就可以安全地使用std::map作为std::setstd::owner_less的关键字执行排序。以上保证weak_ptr的排序即使在容器中过期时也会保持不变。