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

时间:2015-09-01 04:12:28

标签: 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;
}

没有为netither 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

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

3 个答案:

答案 0 :(得分:29)

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

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

Re:&#34;但我的析构函数未被调用&#34;

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

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

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

你的问题为什么&#34; ~B&#34;没有在您的特定代码中调用它,因为您没有在main中捕获异常。如果您更改代码以便main捕获异常,那么&#34; ~B()&#34;将被召唤。但是,当抛出一个没有catch的异常时,实现可以自由地终止程序而不调用析构函数或破坏静态初始化的对象。

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

  

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

     

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

     

...

     

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

答案 1 :(得分:5)

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

答案 2 :(得分:0)

下面是检查销毁顺序(发生时)的示例。

#include <iostream>
#include <stdexcept>
using namespace std;

struct KillMe {
    const char* name;
    KillMe(const char*n): name{n} {clog<<"Hello "<<name<<endl;}
    ~KillMe() {clog<<"Bye "<<name<<endl;}
};
struct CantLive : KillMe {
    KillMe fool{"Fool"}, barf;
    CantLive(): KillMe{"Dady"}, barf{"Barf"} {
        clog<<"Dady cannot live..."<<endl;
        throw logic_error("CantLive cannot live");
    }
};

int main() {
    try {CantLive catch_me;}
    catch(...) {clog<<"Gotcha!"<<endl;}
    clog<<"Now let's try without catcher..."<<endl;
    CantLive dont_catch_me;
    return 0;
}

查看构造和破坏如何发生:

Hello Dady
Hello Fool
Hello Barf
Dady cannot live...
Bye Barf
Bye Fool
Bye Dady
Gotcha!
Now let's try without catcher...
Hello Dady
Hello Fool
Hello Barf
Dady cannot live...
terminate called after throwing an instance of 'std::logic_error'
  what():  CantLive cannot live
exited, aborted
相关问题