2012-03-10 84 views
8

我已经阅读了几篇文章,以及可以从构造函数中抛出异常的地方。但是,我注意到,如果从构造函数中抛出异常,它不会调用基类或其数据成员的析构函数。考虑下面的例子:从构造函数中抛出异常在C++中

#include <iostream> 
using namespace std; 
struct C 
{ 
    C() { cout << __FUNCTION__ << endl; } 
    ~C() { cout << __FUNCTION__ << endl; } 
}; 

struct E: public C 
{ 
    C c; 
    E() { cout << __FUNCTION__ << endl; throw 4; } 
    ~E() { cout << __FUNCTION__ << endl; } 
}; 

int main() 
{ 
    E e; 
} 


$ g++ test.cpp; ./a.exe 
C 
C 
E 
terminate called after throwing an instance of 'int' 
Aborted (core dumped) 

在这种情况下,E的构造函数抛出异常但是C的析构函数作为数据成员或作为基类不被调用。现在,如果C的析构函数像关闭文件/套接字和删除堆分配一样执行一些清理操作,这可能会导致问题。

所以我的问题是为什么和什么时候可以从构造函数中抛出异常。

+0

请注意,如果您在'main'中捕获到异常,则会调用析构函数。见[这里](http://ideone.com/nQemT)。 – 2012-03-10 01:54:59

+0

在您习惯使用异常之前,您可能需要阅读[this](http://stackoverflow.com/questions/1744070/why-should-exceptions-be-used-conservatively)及其相关问题。 – Shahbaz 2012-03-10 02:15:27

回答

12

如果发现错误,将会运行析构函数。当在C++中引发未捕获的异常时,运行时将调用std::terminate。默认情况下,std::terminate调用std::abort,它特别在出路时不调用析构函数。

在这个版本:

#include <iostream> 
using namespace std; 
struct C 
{ 
    C() { cout << __FUNCTION__ << endl; } 
    ~C() { cout << __FUNCTION__ << endl; } 
}; 

struct E: public C 
{ 
    C c; 
    E() { cout << __FUNCTION__ << endl; throw 4; } 
    ~E() { cout << __FUNCTION__ << endl; } 
}; 

int main() 
{ 
    try { 
     E e; 
    } catch(...) { 
    } 

    return 0; 
} 

我得到的输出:

C 
C 
E 
~C 
~C 
+0

多数民众赞成在有趣的。我认为C++会调用析构函数,即使它们没有被处理。 – user236215 2012-03-10 02:04:42

2

我注意到,如果一个异常被抛出它不调用基类或它的数据成员的析构函数从构造函数

是的,它的确如此。

然而,因为你在整个程序不catch是例外,该程序立即终止

如果您要在调用堆栈上方的某处捕获异常,则会按预期方式调用基类和成员的析构函数。

1

您不处理“异常”。

> cat test.cpp 
#include <iostream> 

using namespace std; 
struct C 
{ 
    C() { cout << __FUNCTION__ << endl; } 
    ~C() { cout << __FUNCTION__ << endl; } 
}; 

struct E: public C 
{ 
    C c; 
    E() { cout << __FUNCTION__ << endl; throw 4; } 
    ~E() { cout << __FUNCTION__ << endl; } 
}; 

int main() 
{ 
    try 
    { 
     E e; 
    } 
    catch (int i) 
    { 
     std::cerr << "Handled " << i << std::endl; 
    } 
} 

生成并运行..

> make test 
make: `test' is up to date. 
> ./test 
C 
C 
E 
~C 
~C 
Handled 4 
> 

两个C小号破坏和完全正常的终止。

1
1) E's constructor catched the exception and ran completly. 
    Therefore, its object is created and the distructor is 
    invoked. 

struct C 
{ 
    C() {cout <<__FUNCTION__<< endl;} 
    ~C() {cout <<__FUNCTION__<< endl;} 
}; 

struct E: public C 
{ 
    C c; 
    E() { 
    try { 
     cout <<__FUNCTION__<< endl; 
     throw 4; 
    } 
    catch(int i) { 
    cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl; 
    } 
} 
    ~E() {cout << __FUNCTION__ << endl;} 
void print(){ 
    cout<<"obj of class E is created"<<endl; 
} 
}; 

int main() 
{ 
    try { 
     E e; 
    e.print(); 
} 
catch(int i) { 
    cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl; 
    } 

    return 0; 
} 

/* 
Results: 
C::C 
C::C 
E::E 
int 4 is catched by E::E 
obj of class E is created 
E::~E 
C::~C 
C::~C 
*/ 

2) E's constructor didn’t catch the exception and ran incompletly. 
    In result, its object is not created. Therefore, its distructor 
    is not invoked. 

struct C 
{ 
    C() {cout <<__FUNCTION__<< endl;} 
    ~C() {cout <<__FUNCTION__<< endl;} 
}; 

struct E: public C 
{ 
    C c; 
    E() { 
    try { 
     cout <<__FUNCTION__<< endl; 
     throw 4; 
    } 
    catch(float i) { 
     cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl; 
    }  
} 
    ~E() {cout << __FUNCTION__ << endl;} 
void print(){ 
    cout<<"obj of class E is created"<<endl; 
} 
}; 

int main() 
{ 
    try { 
     E e; 
    e.print(); 
} 
catch(int i) { 
    cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl; 
    } 

    return 0; 
} 

/* 
Results: 
C::C 
C::C 
E::E 
C::~C 
C::~C 
int 4 catched by main function 
*/ 
相关问题