繁体   English   中英

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

[英]`weak_ptr::expired` behavior in the dtor of the object

请考虑以下代码:

#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

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

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

没有。事实上,正如LWG第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]应指定在调用删除器或调用delete p之前对析构函数引起的use_count()减少进行use_count()

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

虽然在调用删除器时意图可能是weak.expired() ,但依赖于此是有问题的。 确实有理由相信, shared_ptr 被销毁不再拥有所有权 - 破坏期间询问这个问题有点奇怪。

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

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

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

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

当发生以下任一情况时,对象将被销毁并释放其内存:

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

shared_ptr的析构函数减少控制块的共享所有者的数量。 如果该计数器达到零,则控制块将调用托管对象的析构函数。 在std :: weak_ptr计数器也达到零之前,控制块不会解除分配。 std :: shared_ptr实施说明

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

not expired
in dtor
expired

是预期的行为。

不是标准本身,但是:

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

检查托管对象是否已被删除。 相当于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()> 1),则没有副作用。
  • 否则,如果*this拥有对象p和删除器d ,则调用d(p)
  • 否则, *this拥有一个指针p ,并调用delete p

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

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

当(紧接着)最后一个shared_ptr停止引用它被销毁的对象时。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM