C++ 无例外和可靠性保证
最近,我试图回答我认为是关于C++ 无例外和可靠性保证,c++,language-lawyer,noexcept,C++,Language Lawyer,Noexcept,最近,我试图回答我认为是关于noexcept异常规范的问题。最终的结果是,我发现我对noexcept的基本理解是错误的 在阅读以纠正误解的过程中,我发现自己问了一些关于noexcept的问题,但没有得到回答 noexcept是否应被视为安全保证,即调用函数时不仅不会抛出,而且不会损坏状态 假设(1.)为false:使用noexcept作为可移植程序来终止应用程序而不进行清理以防止保存状态损坏是否正确 对(2.)的澄清:目的只是防止析构函数从noexcept向上调用堆栈,而不是防止在堆栈中展开。这
noexcept
异常规范的问题。最终的结果是,我发现我对noexcept
的基本理解是错误的
在阅读以纠正误解的过程中,我发现自己问了一些关于noexcept
的问题,但没有得到回答
noexcept
是否应被视为安全保证,即调用函数时不仅不会抛出,而且不会损坏状态noexcept
作为可移植程序来终止应用程序而不进行清理以防止保存状态损坏是否正确noexcept
向上调用堆栈,而不是防止在堆栈中展开。这是基于这样一个假设,即这是一个完美的RAII环境,堆栈上的析构函数可能会清除全局状态以实现持久性,从而破坏它
如何不进行退绕的示例:
#include <iostream>
#include <exception>
namespace{
struct foo{
void change_state() noexcept
{
// change state and fail
throw std::exception();
}
~foo(){
std::cout << "Destructor called, saved state corrupted!" <<std::endl;
}
};
}
int main(){
::std::set_terminate([](){
std::cout<< "Terminate called" <<std::endl;
});
foo f;
f.change_state();
return 0;
}
#包括
#包括
名称空间{
结构foo{
void change_state()无异常
{
//改变状态并失败
抛出std::exception();
}
~foo(){
标准::cout
是的。函数不应该损坏状态、句点,不管它是否抛出。它可能想要抛出异常的事实无关紧要。[当然,不能保证它不会使程序崩溃。不过,这种行为可能应该记录在案。;-]
如果一个函数希望抛出一个noexcept
,它不应该费心抛出;它应该只调用std::terminate
(或者std::abort
)
noexcept
是一种合同担保,非常类似于assert
无法关闭。如果标记为noexcept的函数
尝试通过异常退出,已禁用post条件
违反了,你不能指望任何东西;程序将
终止。因此,1为假
至于2,则更为困难。实施可能会
展开堆栈,直到它尝试使用
noexcept
;它是否可能(至少对我来说)不是100%清楚
不要进一步展开堆栈。如果要终止
没有清理的应用程序,然后我将调用abort()
,这是
保证在不采取任何进一步行动的情况下立即退出
也会准确地告诉读者发生了什么,而不是
指望一个不同功能的副作用。据我所知,noexcept
:即使这个东西抛出,我也不想知道。所以它对“安全性”或“正确性”都不起作用,它的工作原理是防止抛出异常,这样您的程序就不会因此而结束。如果异常到达标记为noexcept
的函数的最外层块,则调用std::terminate
。它根本不抑制异常。它提供了一个屏障,异常可能不会通过我所写的异常e before是关于运行时的,noexcept
在编译时工作,因此它是对编译器的一个提示,编译器会评估您的程序,如果有可能抛出一些东西,您有机会在运行前更正它,因为noexcept
操作符在编译时会失败。它的工作方式类似于类型特征
在某些情况下,您定义了一个需要计算为true
的属性,如果没有,编译器会警告您,如果测试通过,您知道在运行时您将拥有在traits
条件中定义的类型。对于noexcept
,情况也是如此。我认为没有理由相信1)(函数总是会破坏状态,即使没有例外),但我想说2)是正确的。@user2485710我认为您不理解上面问题中的链接标准。这绝对不是noexcept
所做的。有一个标记为noexcept
的函数,其中包含throw
语句,甚至不catch
语句是完全合法的援助抛出。然而,这样做的结果将是调用std::terminate
。我理解你的意思,这种失败应该是明确的,而不是依赖于noexcept
的行为。我想我是在戳理论,当标记为noexcept
的函数调用抛出的函数时。你是否捕捉到exception,然后调用std::terminate
?呃……如果外部函数捕获和处理异常是有用的,那么它当然应该这样做。之后,它可能应该调用terminate
,以证明它不必费心维护类不变量。throw
的一个意思是“但别担心,我们没事。”这么说,如果抛出
距离noexcept
有一英寸的屏幕空间,这没什么大不了的。因此,在这种特殊情况下,你会用捕获
”来包装任何不安全的(非noexcept
)调用,然后调用std::abort
,以防止进一步解除?(我假设在noexcept
函数中展开不会损坏保存的状态)@Mgetz正常情况下,我不会进行任何不安全的调用:-)。否则,如果我想吞下它们,我只会包装它们(例如,通常是在堆栈展开期间调用析构函数的情况)。我的问题似乎不太清楚……其目的只是为了防止析构函数调用比noexcept
更高的堆栈级别。但如果我理解你的意思……你的意思是,在全局保存状态可能损坏的情况下,最好像在noexcept
上下文中那样操作,然后只是中止
If立即需要。@Mgetz当您检测到错误时