【问题标题】:Cannot catch in the initialize list无法在初始化列表中捕获
【发布时间】:2021-09-21 14:31:13
【问题描述】:

对于以下代码:

#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;
}

我试图在 catch 块中捕获异常。但是在catch块运行之后,系统仍然调用std::terminate来终止程序。我没有在catch块中重新抛出异常,你能告诉我为什么系统崩溃了吗?谢谢!

这是对编译器资源管理器的测试:https://godbolt.org/z/74sTcxrY4

【问题讨论】:

  • 函数try-catch块的结束自动重新抛出任何异常

标签: c++


【解决方案1】:

你在自相矛盾。

我试图在 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
}

所以让你在这里吞下异常是没有意义的。您无法处理它,因为您无法返回并重新尝试构建您的成员和基类子对象。如果您没有正确构造的对象,C++ 处理该问题的唯一方法是展开块范围,否则该对象将被假定为......嗯,一个真实的对象。

因此,根据documentation

构造函数的函数try块中的每个catch子句都必须通过抛出异常来终止。如果控件到达此类处理程序的末尾,则当前异常会自动重新抛出,就像 throw; 一样。 return 语句不允许在构造函数的 function-try-block 的任何 catch 子句中。

... 等价于标准 (draft)

如果控制到达构造函数或析构函数的 function-try-block 的处理程序的末尾,则重新抛出当前处理的异常。 否则,从 function-try-block 的处理程序的 compound-statement 的末尾流出等同于从 compound-statement 的末尾流出该函数的(参见[stmt.return])

【讨论】:

  • 干杯,我已经在寻找合适的条款了。我喜欢链接 cppreference,因为它通常更友好,但实际上这个标准非常明确。
【解决方案2】:

没有办法在构造函数的函数 catch 块中吞下异常。如果控制到达 catch 块的末尾,它必然会抛出一些东西,即捕获的异常。解决此问题的唯一方法是 std::terminate 或在此之前中止。

来自cppreference

构造函数的函数try块中的每个catch子句都必须通过抛出异常来终止。如果控件到达此类处理程序的末尾,则当前异常会自动重新抛出,就像 throw; 一样。 return 语句不允许在构造函数的 function-try-block 的任何 catch 子句中。

这是有意和有益的。从未完成的构造函数中返回是没有意义的,尽管实际上并未创建对象,但它允许访问对象。

这样的 catch 块可用于记录错误、释放资源(如果您不使用 RAII)和执行其他类似的清理。但它不能阻止异常传播。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 2020-12-27
    相关资源
    最近更新 更多