2012-03-10 85 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 
*/ 
相關問題