调用删除器时shared_ptr仍然拥有其对象吗?

Rei*_*ica 10 c++ destructor shared-ptr weak-ptr language-lawyer

我有一个std::shared_ptr自定义删除器和删除器,我想采取原始的临时副本std::shared_ptr.以代码形式表示:

struct Foo : public std::enable_shared_from_this<Foo>
{};

void deleter(Foo *f)
{
  {
    std::shared_ptr<Foo> tmp = f->shared_from_this(); // Line A
  }
  delete f;
}

int main()
{
  std::shared_ptr<Foo> foo(new Foo, &deleter);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:在A线上,可以说一下这个电话shared_from_this()吗?这合法吗?如果是这样,标准是否对其返回值有所说明?如果我们enable_shared_from_this用不同的weak_ptr或全局的引用替换foo,那么答案是否相同?

用的libc ++和GCC用的libstdc ++都产生代码终止对bad_weak_ptr例外,但我似乎无法为跟踪这一要求的标准.这是特定于实现的,还是我错过了规则?

我找到的所有相关规则(引用C++ 11):

20.7.2.2.2 shared_ptr析构函数

1 ...如果*this 拥有一个对象p和一个删除器d,d(p)则称为
2 [ 注意: ......由于销毁会*this减少与*this 一个共享所有权的实例数量,在*this销毁之后,所有shared_ptr共享所有权的实例*this将报告一个use_count()比前一个值少一个.- 尾注 ]

20.7.2.2.5 shared_ptr观察员

7 use_count 返回:共享所有权的shared_ptr对象数,或者为空时为0 .*this*this*this

对我来说,似乎还不清楚是否use_count在删除器调用之前或之后发生了减量.获得bad_weak_ptr可靠的结果,还是仅仅未指定?

请注意,我故意避免像tmp我的示例代码中的指针将比删除器执行更长的情况.

Mas*_*nes 13

考虑

[c ++ 14-12.4-15]为对象调用析构函数后,该对象不再存在;

[C++ 14-20.8.2.4-7] shared_from_this()[...]需要:enable_shared_from_this应可访问的基类T的*这应是类型T的对象t的子对象须有在拥有&t的至少一个shared_ptr实例p.

因此,考虑到shared_ptr析构函数调用了删除器,在拥有它的最后一个shared_ptr的删除器中调用shared_from_this()会导致未定义的行为.

编辑:正如YSC所指出的,在C++ 17中, shared_from_this()需要表现为相应的weak_ptr转换调用.这会使问题变得复杂,因为不清楚weak_ptr :: expired()应该在删除器调用时返回...无论如何,20.7.2.2.2从字面上理解引用的注释,在这种情况下应该引发bad_weak_ptr.

  • 确实!我现在明白了.来自[cppreference.com](http://en.cppreference.com/w/cpp/memory/enable_shared_from_this/shared_from_this):_"只允许在先前共享的对象上调用`shared_from_this`,即在被管理的对象上通过`std :: shared_ptr`.否则行为是未定义的(直到C++ 17)`std :: bad_weak_ptr`被抛出(由`shared_ptr`构造函数从默认构造的`weak_this`)(因为C++ 17) )." (2认同)