Nice programing

생성자에서 던진 후 소멸자가 호출 됨

nicepro 2020. 10. 24. 11:43
반응형

생성자에서 던진 후 소멸자가 호출 됨


저는 C ++에서 생성자가 예외를 던지면이 "부분적으로 생성 된"클래스의 소멸자가 호출되지 않는다고 생각했습니다.

하지만 C ++ 11에서는 더 이상 사실이 아닌 것 같습니다. 다음 코드를 g ++로 컴파일하고 " X destructor"를 콘솔에 출력합니다 . 왜 이런거야?

#include <exception>
#include <iostream>
#include <stdexcept>
using namespace std;

class X
{
public:
    X() : X(10)
    {
        throw runtime_error("Exception thrown in X::X()");    
    }
    X(int a)
    {
        cout << "X::X(" << a << ")" << endl;
    }
    ~X()
    {
        cout << "X destructor" << endl;
    }
};

int main()
{
    try
    {
        X x;
    }
    catch(const exception& e)
    {
        cerr << "*** ERROR: " << e.what() << endl;
    }
}

산출

Standard out:
X::X(10) 
X destructor
Standard error: 
*** ERROR: Exception thrown in X::X()

위임 생성자는 실제로 새로운 파괴 로직을 도입하는 새로운 기능입니다.

우리가 방문하자 수명 객체의를 : 때 개체의 수명이 시작 일부 생성자가 완료되었습니다. (15.2 / 2 참조. 표준은 이것을 "주 생성자"라고 부릅니다.) 귀하의 경우 이것은 생성자 X(int)입니다. 두 번째 위임 생성자 X()는 이제 일반 멤버 함수로 작동합니다. 범위가 해제되면 완전히 구성된 모든 객체의 소멸자가 호출되며 여기에는 x.

이것의 의미는 실제로 매우 심오합니다. 이제 생성자에 "복잡한"작업 부하를 넣고 생성자를 다른 생성자에게 위임하는 한 일반적인 예외 전파를 최대한 활용할 수 있습니다. 이러한 디자인은 일반 생성자에 너무 많은 작업을하는 것이 바람직하지 않을 때마다 널리 사용되던 다양한 "init"함수에 대한 필요성을 제거 할 수 있습니다.

사용자가보고있는 동작을 정의하는 특정 언어는 다음과 같습니다.

[C++11: 15.2/2]: [..] 마찬가지로, 객체에 대한 비 위임 생성자가 실행을 완료하고 해당 객체에 대한 위임 생성자가 예외와 함께 종료되면 객체의 소멸자가 호출됩니다. [..]


저는 C ++에서 생성자가 예외를 던지면이 "부분적으로 생성 된"클래스의 소멸자가 호출되지 않는다고 생각했습니다.

그러나 C ++ 11에서는 더 이상 사실이 아닌 것 같습니다.

여전히 사실입니다. C ++ 03 이후 변경된 사항이 없습니다 (일부 값의 경우 ;-))

당신이 생각한 것은 여전히 ​​사실이지만 예외가 던져 질 때 부분적으로 구성된 객체는 없습니다 .

C ++ 03 TC1 표준은 다음과 같이 말합니다.

부분적으로 생성되거나 부분적으로 소멸 된 개체는 완전히 생성 된 모든 하위 개체, 즉 생성자가 실행을 완료하고 소멸자가 아직 실행을 시작하지 않은 하위 개체에 대해 소멸자가 실행됩니다.

i.e. Any object which has completed its constructor will get destroyed by executing the destructor. That's a nice simple rule.

Fundamentally the same rule applies in C++11: as soon as X(int) has returned, the object's "constructor has completed execution" so it is fully constructed, and so its destructor will run at the appropriate time (when it goes out of scope or an exception is thrown during some later stage of its construction.) It's still the same rule, in essence.

The delegating constructor's body runs after the other constructor and can do extra work, but that doesn't change the fact the object's construction has finished, so it is completely constructed. The delegating constructor is analogous to a derived class' constructor, which executes more code after a base class' constructor finishes. In some sense you can consider your example to be like this:

class X
{
public:
    X(int a)
    {
        cout << "X::X(" << a << ")" << endl;
    }
    ~X()
    {
        cout << "X destructor" << endl;
    }
};

class X_delegating : X
{
public:
    X_delegating() : X(10)
    {
        throw runtime_error("Exception thrown in X::X()");    
    }
};

it's not really like this, there's only one type, but it's analogous in as much as the X(int) constructor runs, then additional code in the delegating constructor runs, and if that throws the X "base class" (which isn't really a base class) gets destroyed.

참고URL : https://stackoverflow.com/questions/14386840/destructor-called-after-throwing-from-a-constructor

반응형