2012-03-10 2 views
8

여기에서 여러 기사를 읽었으며 예외적으로 생성자에서 예외를 throw하는 것이 좋습니다. 그러나 생성자에서 예외가 발생하면 기본 클래스 또는 데이터 멤버의 소멸자를 호출하지 않는다는 것을 알았습니다. 다음 예를 고려C++의 생성자에서 예외를 throw하는 중

이때
#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의 소멸자가 파일/소켓 닫기 및 힙 할당 삭제와 같은 정리 작업을 수행하면 문제가 발생할 수 있습니다.

그래서 내 질문에 왜 예외가 생성자에서 예외를 throw 할 수 있습니다.

+0

'main'에서 예외를 잡으면 소멸자가 호출됩니다. [here] (http://ideone.com/nQemT)를 참조하십시오. –

+0

예외 사용에 익숙해지기 전에 [this] (http://stackoverflow.com/questions/1744070/why-should-exceptions-be-used-conservatively) 및 관련 질문을 읽어보십시오. – Shahbaz

답변

12

오류를 잡으면 소멸자가 실행됩니다. catch되지 않은 예외가 C++에서 throw되면 런타임에서 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들 파괴와 완벽하게 정상 종료.

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 
*/ 
관련 문제