c++ - 如果构造函数抛出异常会发生什么?

标签 c++ exception initialization

那我们会得到 UB 吗?

我试过了:

#include <iostream>

struct B
{
    B(){ std::cout << "B()" << std::endl; }
    ~B(){ std::cout << "~B()" << std::endl; }
};

struct A
{
    B b;
    A(){ std::cout << "A()" << std::endl; throw std::exception(); }
    ~A(){ std::cout << "~A()" << std::endl; }
};

int main()
{
    A a;
}

AB 都没有调用析构函数。

实际输出:

B()
A()
terminate called after throwing an instance of 'std::exception'
  what():  std::exception
bash: line 7: 21835 Aborted                 (core dumped) ./a.out

http://coliru.stacked-crooked.com/a/9658b14c73253700

所以任何时候构造函数在 block 范围变量的初始化过程中抛出,我们会得到 UB 吗?

最佳答案

不,抛出异常是在对象构造期间发出错误信号的最佳方式。 (由于没有返回值,除了构造一个 headless 对象之外别无他法,这在 C++ 中是不好的风格。)

来自他本人,Bjarne Stroustrup:http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

(如果您在一个不允许异常的项目中工作,那么您必须使构造函数无误,并将任何可能失败的逻辑移动到有可能返回错误的工厂函数中。)

Re:“但是我的析构函数没有被调用”

确实如此。 在 C++ 中,对象的生命周期从构造函数运行到完成时开始。它在调用析构函数时结束。如果 ctor 抛出,则不调用 dtor。

(但是在 this ctor 运行之前,其 ctors 已经运行完成的任何成员变量对象的 dtors 都会被调用。)

您应该查阅标准或教科书以获取更多详细信息,尤其是。与涉及继承时发生的情况有关。作为一般经验法则,析构函数的调用顺序与构造相反。

您的问题是为什么在您的特定代码中没有调用“~B”,这是因为您没有在 main.c 中捕获异常。如果您更改代码以便 main 捕获异常,则将调用“~B()”。但是,当抛出没有捕获的异常时,实现可以自由地终止程序,而无需调用析构函数或破坏静态初始化的对象。

C++11 标准中的引用(重点是我的):

15.5.1 The std::terminate() function [except.terminate]

1 In some situations exception handling must be abandoned for less subtle error handling techniques.

...

2 In such cases, std::terminate() is called (18.8.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called.

附带说明,一般来说,对于 gcc 和 clang,~B 无论如何都会在您的示例程序中被调用,而对于 MSVC,~B 将不会被调用.异常处理很复杂,标准允许编译器编写者试验并选择他们认为在这方面最好的实现,但他们不能选择给出未定义的行为。

如果在这种情况下调用析构函数对您的程序非常重要,那么您应该确保在 main 中捕获异常,以便您的代码具有可移植性(在所有情况下都一样)符合的编译器)。例如:

int main() {
    try { 
        A a;
    } catch (...) {}
}

这样,像 MSVC 这样的编译器将有义务在退出之前调用 B 的析构函数。

关于c++ - 如果构造函数抛出异常会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32323406/

相关文章:

c++ - 使用指针打印函数地址

c++ - 大量与困惑的 OOP 代码相关的错误

kotlin - 范围是否在幕后默默地处理异常/失败?

powershell - 无法在Powershell的try/catch语句中捕获异常

union 体可以在声明中初始化吗?

c++ - 返回没有拷贝的c++ std::vector?

java - 在 Qt 上使用 java 函数

c# - 让手刹编码器工作

javascript - 初始化变量时,Bash 相当于 Ruby 和 JavaScript OR

python - Django OneToOneField 初始化