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

时间:2017-10-09 12:53:35

标签: c++ language-lawyer destructor shared-ptr weak-ptr

我有一个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);
}

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

带有libc ++的{p> Clang和带有libstdc ++的gcc都会产生终止于bad_weak_ptr异常的代码,但我似乎无法将此跟踪为 required 按标准。这是特定于实现的,还是我错过了规则?

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

  

20.7.2.2.2 shared_ptr析构函数

     

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

     

20.7.2.2.5 shared_ptr观察员

     

7 use_count 返回: shared_ptr个对象的数量,包括*this,与*this共享所有权,或0   当*this为空时。

对我来说,似乎不清楚use_count的减少是在发生删除之前还是之后发生的。获得bad_weak_ptr可靠的结果,还是仅仅是未指定?

请注意,我故意避免在我的示例代码中像tmp这样的指针比删除器执行更久的情况。

1 个答案:

答案 0 :(得分:13)

考虑

  

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

  

[c ++ 14-20.8.2.4-7] shared_from_this ()[...]要求:enable_shared_from_this应该是T的可访问基类。*这应该是一个子对象类型为T的对象t 至少应有一个拥有&amp; t 的shared_ptr实例。

所以,考虑到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。