【问题标题】:Does shared_ptr still own its object when calling the deleter?shared_ptr 在调用删除器时是否仍然拥有它的对象?
【发布时间】:2018-03-20 16:42:08
【问题描述】:

我有一个带有自定义删除器的 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_ptr 或对foo 的全局引用,答案会一样吗?

Clang 与 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 被销毁后,与*this 共享所有权的所有shared_ptr 实例将 报告比其先前值小一的use_count()——尾注]

20.7.2.2.5 shared_ptr观察者

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

对我来说,似乎不清楚use_count 的递减是发生在删除器调用之前还是之后。得到bad_weak_ptr 是一个可靠的结果,还是只是未指定?

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

【问题讨论】:

  • I would like to take a temporary copy of the original std::shared_ptr0_0,为什么?!
  • 如果您不希望tmp 超出删除器的范围,为什么不使用原始指针Foo *f
  • @DavidHaim 关于接口管理、ABI 兼容性和虚拟基类之间转换的复杂框架的长篇故事,所有这些都建立在shared_ptr 之上。
  • @DanielTrugman 与我之前对 David Haim 的回复相同:遗留代码原因。
  • @Angew 相反,我会向 Foo 添加一些名为“move”的虚函数,它会移动指针的内容。如果删除器认为现在不是对象死亡的时间,它会移动它而不是增加引用计数

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


【解决方案1】:

考虑

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

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

因此,考虑到删除器是由 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。

【讨论】:

  • 我不明白 12.4-15 在这里的相关性。你在这里考虑什么析构函数?
  • 好吧,一旦我们输入deleter()main::foo 就不存在了。为什么重要?
  • @YSC,因为如果 foo 不存在,你就违反了 shared_from_this() 前置条件......
  • 真的!我现在明白了。来自cppreference.com: "只允许在先前共享的对象上调用shared_from_this,即在由std::shared_ptr 管理的对象上。否则行为未定义(C++17 前)std::bad_weak_ptr 是抛出(由默认构造的weak_this 中的shared_ptr 构造函数抛出)(C++17 起)。"
  • @YSC,感谢您指出 c++17 的更改,为了完整起见添加到答案...
猜你喜欢
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 2018-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多