C++ 调用删除程序时,shared_ptr是否仍拥有其对象?

C++ 调用删除程序时,shared_ptr是否仍拥有其对象?,c++,language-lawyer,destructor,shared-ptr,weak-ptr,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

我有一个带有自定义删除器的
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);
}
struct Foo:public std::从\u中启用\u共享\u
{};
无效删除器(Foo*f)
{
{
std::shared_ptr tmp=f->shared_from_this();//行A
}
删除f;
}
int main()
{
std::shared_ptr foo(新foo和deleter);
}
我的问题是:在A行,关于从_this()调用
shared\u,可以说些什么吗?这合法吗?如果是这样的话,该标准是否说明了其返回值?如果我们用不同的
弱ptr
或对
foo
的全局引用替换此
中的
启用共享,答案是否相同

使用libc++和libstdc++都会生成终止于
bad\u-weak\u-ptr
异常的代码,但我似乎无法按照标准的要求跟踪这一点。这是特定于实现的,还是缺少规则

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

20.7.2.2.2
shared_ptr
destructor

1。。。如果该
*拥有一个对象
p
和一个删除器
d
,则称为
d(p)
2[注:…由于销毁了
*此
减少了与
*此
共享所有权的实例数量 通过一个,在
*此
被销毁后,与
*此
共享所有权的所有
共享\u ptr
实例将 报告一个小于其上一个值的
使用\u count()
。-结束注释]

20.7.2.2.5
shared\u ptr
observer

7
use\u count
返回与
*此
共享的
对象的数量,包括
*此
,与
*此
共享所有权,或0 当
*此
为空时

对我来说,似乎不清楚
use\u count
的递减是在调用deleter之前还是之后发生的。得到
坏的\u弱的\ptr
是一个可靠的结果,还是这只是一个未指明的结果

请注意,我有意避免示例代码中类似于
tmp
的指针比删除程序的执行时间长的情况

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

[c++14-20.8.2.4-7]共享自\u此()[…]要求:启用自\u共享自\u此应为T的可访问基类。*此应为T类型的对象T的子对象。至少应有一个拥有&T的共享自\u ptr实例p

因此,考虑到删除程序是由共享的\u ptr析构函数调用的,在拥有它的最后一个共享的\u ptr的删除程序中从\u this()调用共享的\u会导致未定义的行为


编辑:正如YSC所指出的,在C++17shared\u from\u中,this()需要作为相应的弱\u ptr转换调用。但这会使事情复杂化,因为还不清楚deleter调用时应该返回什么弱的\u ptr::expired()。。。无论如何,从字面上看,引用的
20.7.2.2.2
注释,在这种情况下,应该提出一个坏的\u弱的\u ptr。

我想临时复制原始std::shared\u ptr
0\u 0,为什么?!如果您不想
tmp
超出删除程序的范围,为什么不使用原始指针
Foo*f
?@DavidHaim讲述了一个复杂的接口管理框架、ABI兼容性和虚拟基类之间的强制转换,所有这些都是在
shared\u ptr
@DanielTrugman的基础上构建的,与我之前对David Haim的回复相同:遗留代码原因。@Angew相反,我将向Foo添加一些名为“move”的虚拟函数,该函数移动指针的内容。如果删除器决定该对象不是死亡时间,它会移动该对象,而不是增加ref count。我不明白12.4-15在这里的相关性。您在考虑什么析构函数?好吧,那么,
main::foo
一旦进入
deleter()
,就不存在了。这有什么关系?@YSC,因为如果foo不存在,你实际上违反了这个()前提条件下的共享\u!我现在明白了。From:“只允许在以前共享的对象上,即在由
std::shared\u ptr
管理的对象上调用
shared\u From\u this
。否则行为未定义(直到C++17)
std::bad\u-weak\u ptr
抛出(由
shared\u ptr
构造函数从默认构造的
weak\u this
抛出)(从C++17开始)。“@YSC,谢谢你指出C++17的变化,为了完整起见,增加了答案。。。