struct base
{
base() { throw std::exception(); }
};
struct derived : public base
{
derived() try : base() { }
catch (std::exception& e)
{
std::cout << "exception handled" << std::endl;
}
};
int main()
{
derived a; // My app crashes.
return 0;
}
不是我的应用写了“处理异常”并继续运行?
我发现的唯一解决方案是在try / catch块中包围“a
”的构造。但是,如果我这样做,那么首先在构造函数中使用try / catch有什么意义呢?我猜也许它的用途是清理可能已分配的成员变量?因为析构函数没有被调用?
以下工作,但处理异常2次。
struct base
{
base() { throw std::exception(); }
};
struct derived : public base
{
derived() try : base() { }
catch(std::exception& e)
{
std::cout << "exception 1" << std::endl;
}
};
int main()
{
// This works fine.
try {
derived a;
}
catch(std::exception& e)
{
std::cout << "exception 2" << std::endl;
}
return 0;
}
我只是想问自己为什么我不应该简单地为构造函数躲避try / catch语法并写下这个:
struct base
{
base() { throw std::exception(); }
};
struct derived : public base
{
derived() : base() { }
};
int main()
{
// This works fine.
try {
derived a;
}
catch(std::exception& e)
{
std::cout << "exception handled" << std::endl;
}
return 0;
}
答案 0 :(得分:9)
function-try-block 不会阻止抛出异常。这是C ++标准草案N4140的摘录,[除了.handle]:
14
如果返回语句出现在构造函数的 function-try-block 的处理程序中,则该程序格式错误。
15
如果控件到达构造函数或析构函数的 function-try-block 的处理程序的末尾,则会重新抛出当前处理的异常。否则,......
原因是如果基类或任何成员构造函数抛出异常,则整个对象的构造失败,并且无法修复它,因此必须抛出异常。 / p>
此处有一个GOTW,底线是
构造函数function-try-block处理程序只有一个目的 - 转换异常。 (也许是为了记录或其他一些副作用。)它们对任何其他目的都没用。
所以,是的,您的上一个代码示例完全正常。
答案 1 :(得分:4)
围绕超类的构造函数包装try / catch可以捕获在超类的构造函数中抛出的异常;但是,当catch
块结束时,异常会自动重新抛出,异常继续传播。
毕竟,超类没有构建。它引发了一个例外。所以你不能真正继续你的快乐方式,在子类的构造函数中,然后最终得到一个构造的子类,但是有一个没有构造的超类。这毫无意义。
来自http://en.cppreference.com/w/cpp/language/function-try-block:
function-try-blocks的主要目的是记录或修改,和 然后重新抛出从成员初始化列表中抛出的异常 构造函数。它们很少与破坏者或常规使用 功能
这实际上是function-try块的主要增值:一个方便的记录位置&#34;嘿,这个函数引发了一个异常&#34;,它包含了整个函数,一个单独的地方来记录这种一件事,但不影响普通的异常处理。