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.2shared_ptr
destructor
1。。。如果该*拥有一个对象p
和一个删除器d
,则称为d(p)
2[注:…由于销毁了*此
减少了与*此
共享所有权的实例数量
通过一个,在*此
被销毁后,与*此
共享所有权的所有共享\u ptr
实例将
报告一个小于其上一个值的使用\u count()
。-结束注释]
20.7.2.2.5shared\u ptr
observer
7use\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的变化,为了完整起见,增加了答案。。。