销毁返回对象
Destruction of returned object
我正在阅读 C++17 standard draft 中第 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_);
}
~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;
}
以上代码输出如下:
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
一般来说,函数的调用者负责销毁函数的 return 值,但具体细节是平台 C++ ABI 的一部分。
在大多数 ABI 上,调用一个 return 具有重要值(任何不能安全地放入一个或两个寄存器中的值)的函数,是通过传递一个隐藏的额外参数来完成的,该参数指定return 应构造值。调用者在其框架中为 return 值分配 space 并传递指向该 space.
的指针
根据 C++17 标准 [except.ctor]/2:
If an exception is thrown during the destruction of temporaries or local variables for a return statement, the destructor for the returned object (if any) is also invoked. The objects are destroyed in the reverse order of the completion of their construction.
然后有一个说明性的例子(你稍微修改了一下)来演示:在 Y
析构函数抛出之后,接下来发生的事情是 A(100)
对象应该被销毁,所以你应该看到销毁消息。
发布的输出表明存在编译器错误。这与报告为 LLVM bug 12286 and gcc bug 33799.
的问题非常相似
后者被标记为已在 GCC 10 中修复(在 2007 年首次报告之后!)。但是,使用 10.0.1 20200418 (experimental)
on Godbolt 版本进行测试:即使 33799 错误报告中的测试用例已修复,但此问题中的代码仍未修复。我在该错误报告中添加了关于此示例的评论。
我正在阅读 C++17 standard draft 中第 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_);
}
~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;
}
以上代码输出如下:
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
一般来说,函数的调用者负责销毁函数的 return 值,但具体细节是平台 C++ ABI 的一部分。
在大多数 ABI 上,调用一个 return 具有重要值(任何不能安全地放入一个或两个寄存器中的值)的函数,是通过传递一个隐藏的额外参数来完成的,该参数指定return 应构造值。调用者在其框架中为 return 值分配 space 并传递指向该 space.
的指针根据 C++17 标准 [except.ctor]/2:
If an exception is thrown during the destruction of temporaries or local variables for a return statement, the destructor for the returned object (if any) is also invoked. The objects are destroyed in the reverse order of the completion of their construction.
然后有一个说明性的例子(你稍微修改了一下)来演示:在 Y
析构函数抛出之后,接下来发生的事情是 A(100)
对象应该被销毁,所以你应该看到销毁消息。
发布的输出表明存在编译器错误。这与报告为 LLVM bug 12286 and gcc bug 33799.
的问题非常相似后者被标记为已在 GCC 10 中修复(在 2007 年首次报告之后!)。但是,使用 10.0.1 20200418 (experimental)
on Godbolt 版本进行测试:即使 33799 错误报告中的测试用例已修复,但此问题中的代码仍未修复。我在该错误报告中添加了关于此示例的评论。