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

ste*_*lla 22 c++ 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;
}
Run Code Online (Sandbox Code Playgroud)

desctructor没有被要求netither A也没有B.实际输出:

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

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

因此,在块范围变量初始化期间构造函数抛出的任何时候,我们都得到UB吗?

Chr*_*eck 42

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

从男人本人,Bjarne Stroustrup:http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

回复:"但我的析构函数没有被称为"

确实.在C++中,对象的生命周期被认为是在构造函数运行完成时开始的.它在调用析构函数时结束.如果ctor抛出,则不会调用dtor.

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

你应该参考标准或一本好的教科书了解更多细节,尤其是 与涉及继承时发生的事情有关.作为一般经验法则,析构函数以相反的构造顺序调用.

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

参考C++ 11标准(强调我的):

15.5.1 std :: terminate()函数 [except.terminate]

1 在某些情况下,必须放弃异常处理以获得不那么微妙的错误处理技术.

...

2 在这种情况下,调用std :: terminate()(18.8.3).在没有找到匹配处理程序的情况下,无论堆栈是否在调用std :: terminate()之前展开,它都是实现定义的.


Ari*_*nhh 5

在构造函数中引发异常是错误处理的标准方式,并且不是未定义的行为。如果抛出构造函数,则假定未正确初始化对象,因此不会调用其析构函数。