对于以下代码:
#include <iostream>
struct Str
{
Str() { throw 100; }
};
class Cla
{
public:
Cla()
try : m_mem() { }
catch(...)
{
std::cout << "Catch block is called"<< std::endl;
}
private:
Str m_mem;
};
int main()
{
Cla obj;
}
Run Code Online (Sandbox Code Playgroud)
我试图在 catch 块中捕获异常。但catch块运行后,系统仍然调用std::terminate来终止程序。我没有在catch块中重新抛出异常,你能告诉我为什么系统崩溃吗?谢谢!
这是对编译器资源管理器的测试:https://godbolt.org/z/74sTcxrY4
Use*_*ess 10
你这是自相矛盾。
我试图在 catch 块中捕获异常。但是在 catch 块运行之后
如果运行 catch 块,则您成功从初始值设定项列表中捕获异常。你只是对接下来发生的事情感到惊讶。
首先,让我们考虑一下当构造函数抛出异常时会发生什么:对象没有被构造。正确的?构造函数从未完成它的设置,因此您不能将它用于任何用途。
int main() {
Cla obj; // member subobject constructor throw, but we caught it!
obj.print(); // but we still can't use this here, because the constructor never completed
}
Run Code Online (Sandbox Code Playgroud)
所以让你在这里吞掉异常并没有什么意义。您无法处理它,因为您无法返回并重新尝试构造您的成员和基类子对象。如果没有正确构造的对象,C++ 处理该问题的唯一方法是展开块作用域,否则该对象将被假定为……嗯,一个真实的对象。
因此,根据文档:
构造函数的函数 try 块中的每个 catch 子句都必须通过引发异常来终止。如果控件到达此类处理程序的末尾,则将自动重新抛出当前异常,就像通过 throw; 一样。构造函数的函数 try 块的任何 catch 子句中都不允许使用 return 语句。
...以及标准(草案)中的同等内容
如果控制到达构造函数或析构函数的函数 try 块的处理程序末尾,则重新抛出当前处理的异常。否则,从函数 try 块的处理程序的复合语句的末尾流出相当于从该函数的复合语句的末尾流出(请参阅 [stmt.return])
无法在构造函数的函数 catch 块中吞掉异常。如果控制到达 catch 块的末尾,它必然会抛出一些东西,即捕获的异常。解决此问题的唯一方法是在此std::terminate之前终止或以其他方式中止。
来自cppreference:
构造函数的函数 try 块中的每个 catch 子句都必须通过引发异常来终止。如果控件到达此类处理程序的末尾,则将自动重新抛出当前异常,就像通过 throw; 一样。构造函数的函数 try 块的任何 catch 子句中都不允许使用 return 语句。
这是有意而为之、有益的。从未完成的构造函数返回是没有意义的,它将允许对象可访问,尽管实际上尚未创建。
这样的 catch 块可用于记录错误、释放资源(如果您不使用 RAII)以及执行其他类似的清理。但它无法阻止异常的传播。