为什么 C++ 中的强制 RVO 需要 public 析构函数?
Why is public destructor necessary for mandatory RVO in C++?
请考虑下面的简单示例,其中函数 bar
return 是 class A
的对象,具有私有析构函数,并且强制性 return 必须进行价值优化 (RVO):
class A { ~A() = default; };
A bar() { return {}; }
代码被 Clang 接受,但被 GCC 拒绝并出现错误:
error: 'constexpr A::~A()' is private within this context
2 | A bar() { return {}; }
| ^
https://gcc.godbolt.org/z/q6c33absK
哪一位编译器就在这里?
这是CWG 2426。在此上下文中可能会调用析构函数,因为即使在 return A
对象初始化之后,该函数仍有可能无法成功完成:在 return
语句期间创建的任何临时对象和范围内的自动局部变量必须被销毁,如果销毁抛出,那么作为堆栈展开的一部分,A
对象被销毁。编译器应该 要求此时可以访问析构函数。
注1:函数最外层作用域的局部变量的析构函数抛出的异常可以被函数try块捕获。
注2:在return对象销毁后,允许handler执行另一个return
语句。标准中有一个这样的例子。
有很多像问题中这样的简单情况,可以很容易地证明永远不会使用析构函数,但是使用了代码。
虽然决定这个问题可能会变得任意复杂,这是标准化的祸根。将它留在实施者手中将因此分裂语言,创建不兼容的子方言,因为他们会付出不同的努力来决定(不同的)极端情况。
但这还不是结束,因为解决问题意味着解决停机问题,因此 甚至不是难以处理的,而是不可判定的.
因此,像 CWG 2426 那样回避它不仅是为了理智(指定所有细节变得非常笨重),而且是唯一的选择,而不是在口述任意数量的任意选择后随意画一条线简单的案例。
请考虑下面的简单示例,其中函数 bar
return 是 class A
的对象,具有私有析构函数,并且强制性 return 必须进行价值优化 (RVO):
class A { ~A() = default; };
A bar() { return {}; }
代码被 Clang 接受,但被 GCC 拒绝并出现错误:
error: 'constexpr A::~A()' is private within this context
2 | A bar() { return {}; }
| ^
https://gcc.godbolt.org/z/q6c33absK
哪一位编译器就在这里?
这是CWG 2426。在此上下文中可能会调用析构函数,因为即使在 return A
对象初始化之后,该函数仍有可能无法成功完成:在 return
语句期间创建的任何临时对象和范围内的自动局部变量必须被销毁,如果销毁抛出,那么作为堆栈展开的一部分,A
对象被销毁。编译器应该 要求此时可以访问析构函数。
注1:函数最外层作用域的局部变量的析构函数抛出的异常可以被函数try块捕获。
注2:在return对象销毁后,允许handler执行另一个return
语句。标准中有一个这样的例子。
有很多像问题中这样的简单情况,可以很容易地证明永远不会使用析构函数,但是使用了代码。
虽然决定这个问题可能会变得任意复杂,这是标准化的祸根。将它留在实施者手中将因此分裂语言,创建不兼容的子方言,因为他们会付出不同的努力来决定(不同的)极端情况。
但这还不是结束,因为解决问题意味着解决停机问题,因此 甚至不是难以处理的,而是不可判定的.
因此,像 CWG 2426 那样回避它不仅是为了理智(指定所有细节变得非常笨重),而且是唯一的选择,而不是在口述任意数量的任意选择后随意画一条线简单的案例。