2015-02-05 2 views
12

catch 블록 범위를 벗어날 때 예외 소멸자가 호출됩니까? (우리가 다시 던지 지 않는 경우)비 가상 소멸자 C++

클래스 A가 있고 소멸자가 가상이 아니라고 가정합니다. B는 예외 소멸자 경우에, 캐치 범위를 벗어난다 이동 호출하는 경우 A. 일부 기능은 예외 으로 B 클래스의 객체를 던지고가 캐치 블록

catch(A& a){ 
... 
} 

의해 잡힌 가정 상속 이 경우에는 기본 클래스 A의 소멸자 만 호출됩니다.

옥수수 : 두 클래스 소멸자를 호출하여 실시간 평가판 사용 결과.

내 논리와 모순됩니다. 누군가를 설명해 주시겠습니까?

+1

나는이 질문을하는 이유에 약간 관심이있다. 이것은 매우 유효하고 기본적인 질문은 아니지만 예외의 소멸자가 호출 된 시점에 대해 관심이 있다는 것을 나타냅니다. 이는 일반적으로하는 일이 아닙니다. –

+0

어, 그 마지막 부분에 대해 잘 모르겠습니다. –

+0

@ MarcusMüller : 우리가 사용하는 도구에 대한 지식을 얻고 자하는 것이 잘못된 이유는 무엇입니까? –

답변

5

누군가가 이미 첫 번째 질문에 답변했습니다. 여기에 초점을 맞출 것입니다 :

예외 소멸자가 catch 범위를 벗어날 때 호출되어야한다면,이 경우 기본 클래스 A의 토르만 호출됩니다.

구현은 예외 객체가 잡히는 방식과 관계없이 항상 예외 객체를 적절하게 파괴합니다. 구현은 예외 객체를 구성하므로 파기하는 방법을 알고 있습니다. 포인터를 통해 delete을 호출 할 때와 같지 않습니다.이 경우 가상 소멸자가 존재하지 않는 한 그 시점에서 객체의 전체 유형에 대한 불완전한 정보가 있습니다 (new 다른 곳에서 편집되었을 수 있습니다).

그렇지 않은 경우, catch (...)은 전혀 작동하지 않습니다.

+0

(다른 곳에서 새롭게 선보였을 수도 있습니다) - 설명해주세요. –

+3

그리고 완벽을 기하기 위해 기본 형식에 대한 포인터를 통해 파생 개체에 대한 포인터를 삭제하면 기본 형식에 가상 소멸자가 없어 ** 정의되지 않은 동작 **이 생성됩니다. 기본 소멸자가 실행될 수 있지만 완전히 다른 작업을 수행 할 수 있습니다. –

+0

@Day_Dreamer 죄송 합니다만, 어색한 문장이었습니다.하지만 요점은 포인터가'delete'd 인 코드에서 포인터가 같은 객체가있는 곳과 일치시킬 방법이 없다는 것입니다. 새로운 것. 그래서 가상 소멸자가 필요합니다. 그렇지 않으면 코드가 소멸자를 호출 할 "알 수있는"방법이 없습니다. – Brian

5

catch 블록 범위를 벗어날 때 예외 소멸자가 호출됩니까?

있음 (여기서 우리는 그것을 다시 발생하지 않는다)

[C++11: 15.1/4]:[...] 예외 객체가 어떠한 방법으로 예외 이탈의 마지막 남은 활성 핸들러 중 후 소멸 또는 예외 오브젝트를 참조하는 유형 std::exception_ptr (18.8.5)의 마지막 오브젝트가 파기 되었 는가? [..] 캐치 범위 밖으로 갈 때 예외 소멸자이 경우, 호출하는 경우는


는 기본 클래스 A의 디부 토르는 를 호출 할 것인가?

No

:

#include <iostream> 

struct A 
{ 
    A() { std::cout << "A()"; } 
    A(const A&) { std::cout << "A(const A&)"; } 
    A(A&&) { std::cout << "A(A&&)"; } 
    ~A() { std::cout << "~A()"; } 
}; 

struct B : A 
{ 
    B() { std::cout << "B()"; } 
    B(const B&) { std::cout << "B(const B&)"; } 
    B(B&&) { std::cout << "B(B&&)"; } 
    ~B() { std::cout << "~B()"; } 
}; 

int main() 
{ 
    try { 
     throw B(); 
    } 
    catch (A&) { 
    } 
} 

// Output: A()B()~B()~A() 
+0

사실, 당신의 샘플은 그렇지 않다는 것을 나타낸다. ~ B() ~ A() – zdan

+1

Ahem, Lightness, 당신의 coliru 링크는'~ B()'와'~ A()'가 출력되는 것을 보여줍니다. Cornstalks의 대답이 확인하는 바로는 ... 그냥 ' –

+0

@InnocentBystander :'~ B() '가 _throw-expression_의 일시적인 것인지, 아니면 그것이 합법적인지 아닌지 여부를 알 수 없다고 생각합니다. '캐치 (catch) '에서 출력물을 볼 수 있습니다. –

3

내가 표준에서 인용하고 있지 않다 있지만, A&B을 던지고 잡는 것은 모두 A가 발생합니다 's 및 B의 소멸자가 호출 점점 것으로 보인다. Live demo :

#include <iostream> 

struct A 
{ 
    ~A() { std::cout << "A::~A" << std::endl; } 
}; 

struct B : public A 
{ 
    ~B() { std::cout << "B::~B" << std::endl; } 
}; 

void throwit() 
{ 
    throw B{}; 
} 

int main() 
{ 
    std::cout << "beginning main scope" << std::endl; 

    { 
     std::cout << "beginning inner scope" << std::endl; 

     try 
     { 
      std::cout << "calling throwit()" << std::endl; 
      throwit(); 
     } 
     catch (A& a) 
     { 
      std::cout << "caught exception" << std::endl; 
     } 

     std::cout << "ending inner scope" << std::endl; 
    } 

    std::cout << "ending main scope" << std::endl; 
} 

출력 :

시작 주요 범위
시작 내측 범위

잡힌 예외
B : ~ B
:: ~
을하여 throwit()를 호출 끝내는 범위
결말 주요 범위

두 소멸자가 모두 호출됩니다. 여분의 범위 인쇄는 소멸자가 호출 될 때를 매우 명확하게 보여줍니다 (catch 블록 끝 부분).

3

표준이 개체가 파괴되었다고 말할 때마다 가장 많이 파생 된 올바른 소멸자가 호출됨을 의미합니다.

항상.

가상 소멸자가없는 개체를 다형 적으로 삭제하거나 불완전한 형식의 개체를 종료 (delete 연산자 또는 명시 적 소멸자 호출을 통해)하고 적절한 소멸자가 중요하지 않은 경우 해당 개체가 소멸되었다고 표시하지 않습니다 . 기본 클래스 소멸자가 호출되었다고하지는 않습니다. 정의되지 않은 동작이 있다고합니다.