2012-03-10 6 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のデストラクタがファイル/ソケットのクローズやヒープ割り当ての削除などのクリーンアップ操作を実行すると、問題が発生する可能性があります。

私の質問はなぜですか、そしてコンストラクタから例外をスローするのはいつかOKです。

+0

「main」で例外をキャッチすると、デストラクタが呼び出されることに注意してください。 [here](http://ideone.com/nQemT)を参照してください。 –

+0

例外を使用する前に、[this](http://stackoverflow.com/questions/1744070/why-should-exceptions-be-used-conservatively)とそれに関連する質問をお読みください。 – Shahbaz

答えて

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

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 sが破壊し、完全に正常終了。

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 
*/ 
関連する問題