对象dtor中的`weak_ptr :: expired`行为

时间:2017-01-25 12:20:41

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

请考虑以下代码:

#include <iostream>
#include <memory>
using namespace std;

class T;

std::weak_ptr<T> wptr;

class T
{
public:
    T() {  }
    ~T() {
        std::cout << "in dtor" << std::endl;
        std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
    }
};

int main() {
    {
        auto ptr = std::make_shared<T>();
        wptr = ptr;
        std::cout << (wptr.expired() ? "expired" : "not expired") << std::endl;
    }
    return 0;
}

在此代码中,我试图找出对象销毁阶段中weak_ptr是否已过期。看来是这样。输出是:

not expired
in dtor
expired

我将gcc-5.1与ideone一起使用。

现在,我有另一个问题。我找不到任何文档说明这是标准行为。是否保证以这种方式工作,始终

4 个答案:

答案 0 :(得分:8)

  

现在,我有另一个问题。我找不到任何文件说明这是标准行为。是否保证以这种方式工作,始终

没有。实际上,正如LWG issue 2751提出的那样,它在标准中没有明确规定。

  

C ++ 14标准不包含任何语言,以保证shared_ptr运行删除器会将所有关联的weak_ptr实例视为已过期。例如,标准似乎并不能保证以下代码段中的断言不会被解雇:

std::weak_ptr<Foo> weak;
std::shared_ptr<Foo> strong{
  new Foo,
  [&weak] (Foo* f) {
    assert(weak.expired());
    delete f;
  },
};

weak = strong;
strong.reset();
     

似乎很明显,目标是关联的weak_ptr已过期,因为否则shared_ptr删除者可以恢复对正在删除的对象的引用。

     

建议修复:23.11.3.2 [util.smartptr.shared.dest]应指定在调用删除符或调用use_count()之前对析构函数引起的delete p减少进行排序。

上面链接的~shared_ptr()的当前措辞仅表示调用了删除操作,并且非规范性地说明共享所有权的实例数量减少了。

虽然调用删除器的意图可能是weak.expired(),但依赖于此是有问题的。确切地说明shared_ptr在被销毁之后不再共享所有权是非常合理的 - 在期间提出问题破坏有点奇怪。

答案 1 :(得分:5)

像这样使用make_shared将使用您提供的默认构造函数创建一个对象。

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
  

构造一个T类型的对象并将其包装在std::shared_ptr中   使用args作为T的构造函数的参数列表。该对象   就像表达式(std::make_shared

一样构造

在主要的匿名范围之后。共享的ptr将被删除。

  

当任何一个对象被破坏并且其内存被释放时,该对象被解除   发生以下情况:

     

拥有该对象的最后剩余的shared_ptr被销毁;   (std::shared_ptr

  

shared_ptr的析构函数减少了共享所有者的数量   控制块。如果该计数器达到零,则控制块   调用托管对象的析构函数。控制块没有   释放自己直到std :: weak_ptr计数器达到零为止   好。 std::shared_ptr Implementation notes

这意味着您的对象将在最后一个共享ptr的破坏开始后调用其析构函数。 输出:

not expired
in dtor
expired

是预期的行为。

答案 2 :(得分:0)

不是标准本身,但是:

http://en.cppreference.com/w/cpp/memory/weak_ptr/expired

  

检查托管对象是否已被删除。当量   to use_count()== 0。

因此,在删除之前或之后将天气use_count设置为0成为问题。现在标准草案中没有这个: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf [第566页20.9.2.2.2]

  

~shared_ptr();

     

效果:

     
      
  • 如果*this为空或与另一个shared_ptr实例共享所有权(use_count()&gt; 1),则无副作用。
  •   
  • 否则,如果*this拥有对象p和删除者d,则会调用d(p)
  •   
  • 否则,*this拥有指针p,并且会调用delete p
  •   
     

[注意:由于*this的破坏减少了数量   在*this之后,与*this共享所有权的实例   已销毁所有共享所有权的shared_ptr个实例   *this会报告比之前少一个的use_count()   值。 - 结束说明]

答案 3 :(得分:0)

weak_ptr没有引用该对象时,shared_ptr到期。

当最后一个shared_ptr停止时(紧接其后)引用该对象时,它被摧毁。

此时没有shared_ptr引用它,因此任何weak_ptr都已过期。

现在调用了对象的析构函数,如果它有单独的存储(即没有用make_shared创建),则会释放其存储空间。

如果存在引用它的任何weak_ptr,则存储引用计数和原始指针以及删除功能的控制块将一直存在。当最后一个weak_ptr停止引用它时,控制块也会被销毁并解除分配。即,shared_ptr实例使对象本身及其控制块保持活动状态,而weak_ptr实例使控制块保持活动状态。