C++ 销毁返回的对象
我正在阅读第18节异常处理的第18.2小节构造函数和析构函数,其中有一个示例(第384页)。我试图理解在try块中返回的对象A的销毁发生在哪里,但找不到。因此,我复制了这个示例,添加了一些打印,并看到从未调用该对象的dtor。我错过了什么?有人请解释一下这里发生了什么C++ 销毁返回的对象,c++,exception,return-value,destructor,throw,C++,Exception,Return Value,Destructor,Throw,我正在阅读第18节异常处理的第18.2小节构造函数和析构函数,其中有一个示例(第384页)。我试图理解在try块中返回的对象A的销毁发生在哪里,但找不到。因此,我复制了这个示例,添加了一些打印,并看到从未调用该对象的dtor。我错过了什么?有人请解释一下这里发生了什么 #include <stdio.h> struct A { int a_; explicit A(int a):a_(a) { printf("A(%d)'s ctor\n", a_)
#include <stdio.h>
struct A {
int a_;
explicit A(int a):a_(a) {
printf("A(%d)'s ctor\n", a_);
}
~A() {
printf("A(%d)'s dtor\n", a_);
}
};
struct Y { ~Y() noexcept(false) {
printf("y's dtor\n");
throw 0; } };
A f() {
try {
A a(23);
Y y;
A b(56);
return A(100); // #1 who destructs this ??
} catch (...) {
printf("handling exception..\n");
}
printf("At line %d now..\n", __LINE__);
return A(200); // #2
}
int main() {
auto ret = f();
printf("f returned A(%d) object\n", ret.a_);
return 0;
}
一般来说,函数的调用方负责破坏函数的返回值,但是精确的细节是平台C++ +ABI的一部分。
在大多数ABI上,调用一个返回非平凡值的函数(任何不能安全地放入一个或两个寄存器的函数)是通过传递一个隐藏的额外参数来完成的,该参数指定了返回值应该在哪里构造。调用者在其帧中为返回值分配空间,并传递指向该空间的指针。根据C++17标准[except.ctor]/2: 如果在为return语句销毁临时变量或局部变量期间引发异常,则还将调用返回对象(如果有)的析构函数。这些物品的销毁顺序与完成建造的顺序相反 然后有一个示例(您稍微修改了一下)来演示:
Y
析构函数抛出后,接下来发生的事情是A(100)
对象应该被销毁,因此您应该看到一条销毁消息
发布的输出表明存在编译器错误。这与和报告的问题非常相似
后者在GCC 10中被标记为固定(在2007年首次报告之后!)。但是,使用版本
10.0.1 20200418(实验版)
进行测试:即使33799错误报告中的测试用例已修复,此问题中的代码仍未修复。我在该bug报告中添加了一条关于该示例的注释。您已经演示了为什么析构函数永远不能安全地抛出异常。您链接的文档是c++17之后的草稿(请参阅N4659了解c++17标准)@chrisdd不太可能,这个程序应该定义得很好。问题是析构函数上允许任何异常的任何异常规范都不可能安全实现,因为在帧完全销毁之前退出帧时可能会抛出异常。@chrisdd标准没有提到“帧”,该示例与问题非常相似。@TonyTannous是的,我假设OP查看了该示例并添加了一些输出调试这在标准中似乎是一个糟糕的问题——实现这一点需要在存在可能引发异常的对象的每一帧中增加大量开销(我想这还不算太糟,因为没有真正的程序会声明析构函数noexcept(false))@chrisdd如果编译器供应商有意违反标准,那么他们的bug追踪器上应该有一个讨论线程(尽管搜索这些东西可能是一场噩梦)如果我理解正确,调用方(main
此处)退出并且ret
被破坏,如第A(200)行的dtor所示。在它之前的某个地方,我希望看到第A(100)行's的dtor
,这让我很困惑。也许,我需要了解您提到的在析构函数中抛出异常的细微差别和其他细节!@VishalSahu标准明确地说,在A(100)
,类型A的返回对象被构造。然后,局部变量b被销毁(8.7)。接下来,局部变量y被销毁,导致堆栈展开,导致返回对象的销毁,然后是局部变量a的销毁
A(23)'s ctor
A(56)'s ctor
A(100)'s ctor
A(56)'s dtor
y's dtor
A(23)'s dtor
handling exception..
At line 34 now..
A(200)'s ctor
f returned A(200) object
A(200)'s dtor
...Program finished with exit code 0