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

jnb*_*mez 16 c++ shared-ptr weak-ptr c++11 c++14

请考虑以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

not expired
in dtor
expired
Run Code Online (Sandbox Code Playgroud)

我用gcc-5.1和ideone.

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

Bar*_*rry 8

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

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

C++ 14标准不包含任何语言,该语言保证由a运行的删除器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();
Run Code Online (Sandbox Code Playgroud)

似乎很清楚,意图是关联的weak_ptrs已过期,因为否则shared_ptr删除者可以恢复对正被删除的对象的引用.

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

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

虽然意图可能是weak.expired()在调用删除器时,依赖于此是有问题的.shared_ptr确切地说,它被摧毁之后不再拥有所有权是真的是合理的 - 破坏期间询问这个问题有点奇怪.


Pet*_*lev 5

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

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

.

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

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

not expired
in dtor
expired
Run Code Online (Sandbox Code Playgroud)

是预期的行为.


Lan*_*ing 0

不是标准本身,而是:

\n\n

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

\n\n
\n

检查管理对象是否已被删除。相当于\n use_count() == 0。

\n
\n\n

use_count所以这就变成了删除之前或之后天气设置为0的问题。现在标准草案中没有提到这一点:\n http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf [第 566 页 20.9.2.2 .2]

\n\n
\n

~shared_ptr();

\n\n

效果:

\n\n
    \n
  • 如果*this为空或与另一个shared_ptr实例共享所有权 (use_count() > 1),则没有副作用。
  • \n
  • 否则,如果*this拥有一个对象p和一个删除器dd(p)则被调用。
  • \n
  • 否则,*this拥有一个指针p,并被delete p调用。
  • \n
\n\n

[注意:由于 的销毁会使*this共享所有权的实例数量减少 1 *this,因此在*this销毁后,所有与其shared_ptr共享所有权的实例 *this将报告use_count()比之前的值少 1 的值。\xe2\x80\x94 尾注]

\n
\n

  • 注释仍然没有明确指定顺序,不是吗? (3认同)