[英]Should throw() function always unwind stack on exception and allow exception to be catched or std::terminate must be called?
我很感兴趣这是否是由标准强制执行的,以及是否被某些编译器所违反。 我的观察是:
gcc(6.3.0),未取消throw()函数中的堆栈,但随后调用了std :: terminate(try / catch无法解决异常)。 但是使用7.0(当前HEAD)时,没有取消堆栈堆栈,因此立即调用std :: termiante。 实际上,gcc 7.0甚至对此发出警告: warning: throw will always call terminate() [-Wterminate]
为NoExceptFunctionWithObj2()
warning: throw will always call terminate() [-Wterminate]
。 它使throw()的行为与noexcept(true)相同。
在所有版本中,我都检查过展开函数堆栈(调用了对象d-tors),然后调用了std :: terminate。
#include <iostream>
#include <string>
#include <vector>
struct TestDataWithoutNoexcept {
TestDataWithoutNoexcept() {
std::cout << __FUNCTION__ << "\n";
}
~TestDataWithoutNoexcept() {
std::cout << __FUNCTION__ << "\n";
}
TestDataWithoutNoexcept(TestDataWithoutNoexcept const & rhs) {
std::cout << __FUNCTION__ << "\n";
}
TestDataWithoutNoexcept(TestDataWithoutNoexcept && rhs) {
std::cout << __FUNCTION__ << "\n";
}
TestDataWithoutNoexcept& operator=(TestDataWithoutNoexcept const& rhs) {
std::cout << __FUNCTION__ << "\n";
}
};
void NoExceptFunctionWithObj1() noexcept {
TestDataWithoutNoexcept test;
throw std::runtime_error("NoExceptFunctionWithObj1 ex.");
}
void NoExceptFunctionWithObj2() throw() {
TestDataWithoutNoexcept test;
throw std::runtime_error("NoExceptFunctionWithObj2 ex.");
}
int main()
{
// Now lets see whether stack is being unwound when exception is thrown in noexcept versus throw() function.
std::cout << "\n See how dtors are called in noexcept or throw() functions\n";
try {
//NoExceptFunctionWithObj1();
}
catch (std::runtime_error& ex) {
std::cout << ex.what();
}
try {
NoExceptFunctionWithObj2();
}
catch (std::runtime_error& ex) {
std::cout << "\nShouldn't this be shown? : " << ex.what();
}
}
是的,应该调用std::terminate
。 最新发布的标准草案说:
15.4 [规格除外],第12段
如果异常规范的形式为throw(),noexcept或noexcept(constant-expression),其中常量表达式产生true,则该异常规范为非抛出。
这意味着throw()
严格等同于noexcept(true)
。 在C++17
不推荐使用throw()
。
15.5.1 [终止除外]
在处理程序(15.3)的搜索遇到带有noexcept-spec的函数的最外面的块时,该函数不允许出现异常(15.4)[...] std :: terminate()(18.8.3)。 在找不到匹配处理程序的情况下,由实现定义是否在调用std :: terminate()之前取消堆栈的堆栈
不调用std::terminate
表示MSVC不兼容。
关于堆栈的处理,在您的示例中,编译器会执行它希望对其进行展开或不展开的操作-这被指定为实现定义的 。
历史上(在C ++ 11之前)在这种情况下必须进行堆栈展开。 然而,事实证明,这种强制行为的运行时成本太高,并且它抑制了编译器进行某些优化(即使在非异常情况下)。 结果,编译器现在可以自由地将其省略。
经过@mike澄清后进行编辑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.