문제

class someclass {};

class base
{
    int a;
    int *pint;
    someclass objsomeclass;
    someclass* psomeclass;
public:
    base()
    {
        objsomeclass = someclass();
        psomeclass = new someclass();
        pint = new int(); 
        throw "constructor failed";
        a = 43;
    }
}

int main()
{
    base temp();
}

위 코드에서 생성자는 던졌습니다. 어떤 물체가 누출되고, 메모리 누출을 어떻게 피할 수 있습니까?

int main()
{
    base *temp = new base();
}

위 코드는 어떻습니까? 생성자가 던진 후에 메모리 누출을 어떻게 피할 수 있습니까?

도움이 되었습니까?

해결책

예, 메모리 누출이 발생합니다. 생성자가 던지면 소멸자가 호출되지 않습니다 (이 경우 동적으로 할당 된 물체를 해방시키는 소멸자가 표시되지 않지만 하나가 있다고 가정하자).

이것은 스마트 포인터를 사용하는 주요 이유입니다. 스마트 포터는 완전한 깃발 물체이기 때문에 예외의 스택이 풀리고 메모리를 풀 수있는 기회를 갖게됩니다.

boost의 scoped_ptr <> 템플릿과 같은 것을 사용하는 경우 클래스가 더 많이 보일 수 있습니다.

class base{
    int a;
    scoped_ptr<int> pint;
    someclass objsomeclass;
    scoped_ptr<someclass> psomeclass;
    base() : 
       pint( new int),
       objsomeclass( someclass()),
       psomeclass( new someclass())

    {
        throw "constructor failed";
        a = 43;
    }
}

메모리 누출이 없을 것입니다 (기본 DTOR도 동적 메모리 할당을 정리할 수 있습니다).


요약하면 (그리고 이것은 또한 이것은 또한

base* temp = new base();

성명):

생성자 안에 예외가 발생하면 객체의 낙태 된 구성에서 발생했을 수있는 자원 할당을 적절히 처리하는 데 주목해야 할 몇 가지 사항이 있습니다.

  1. 구성되는 대상의 소멸자는 의지합니다 ~ 아니다 불리다.
  2. 해당 개체의 클래스에 포함 된 멤버 객체의 소멸자는 호출됩니다.
  3. 구성된 물체에 대한 메모리가 해제됩니다.

즉, 객체가 자원을 소유하고 있으면 생성자가 던질 때 이미 획득했을 수있는 리소스를 정리할 수있는 2 가지 방법이 있습니다.

  1. 예외를 잡고 리소스를 해제 한 다음 재검토하십시오. 이것은 정확해지기가 어려울 수 있으며 유지 보수 문제가 될 수 있습니다.
  2. 물체를 사용하여 자원 수명 (RAII)을 관리하고 해당 객체를 멤버로 사용하십시오. 객체의 생성자가 예외를 던지면, 멤버 객체는 desctructors를 호출하고 수명이 담당하는 자원을 해방시킬 수있는 기회를 갖게됩니다.

다른 팁

두 사람 모두 유출 될 것입니다.

생성 된 객체의 주소를 할당하십시오 명명 된 스마트 포인터는 예외가 발생할 때 호출을받는 스마트 포인터 파괴자 내부에서 삭제되도록 - (raii).

class base {
    int a;
    boost::shared_ptr<int> pint;
    someclass objsomeclass;
    boost::shared_ptr<someclass> psomeclass;

    base() :
        objsomeclass( someclass() ),
        boost::shared_ptr<someclass> psomeclass( new someclass() ),
        boost::shared_ptr<int> pint( new int() )
    {
        throw "constructor failed";
        a = 43;
    }
};

지금 psomeclass & 파인트 생성자에 예외가 발생하면 스택이 풀릴 때 파괴자가 호출되며 해당 소멸자는 할당 된 메모리를 처리합니다.

int main(){
    base *temp = new base();
}

생성자가 예외를 던지면 연산자에 의해 할당 된 새, 새로운, 메모리를 사용한 일반 메모리 할당의 경우, 새로운 경우 새로 할당 된 메모리가 자동으로 해제됩니다. 개별 회원을 자유롭게하는 이유 (Mike B의 답변에 대한 의견에 대한 응답으로), 자동 해방은 다른 경우가 아니라 새로운 객체의 생성자에 예외가 발생하는 경우에만 적용됩니다. 또한, 해방 된 메모리는 생성자 내부에 말할 수있는 메모리가 아니라 객체 멤버에 할당 된 메모리입니다. 즉, 멤버 변수의 메모리를 해방시킬 것입니다. , 파인트, objsomeclass, 그리고 psomeclass, 그러나 메모리가 할당되지 않았습니다 새로운 someclass () 그리고 새로운 int ().

나는 최고 답변이 잘못되었고 여전히 메모리를 누출 할 것이라고 생각합니다. 클래스 멤버를위한 소멸자 ~ 아니다 생성자가 예외를 던지면 (초기화를 완료하지 않았으므로, 일부 구성원이 생성자 호출에 도달 한 적이 없기 때문에) 호출됩니다. 그들의 소멸자는 계급의 소멸자 호출 중에 만 호출됩니다. 그것은 단지 의미가 있습니다.

이 간단한 프로그램은 그것을 보여줍니다.

#include <stdio.h>


class A
{
    int x;

public:
    A(int x) : x(x) { printf("A constructor [%d]\n", x); }
    ~A() { printf("A destructor [%d]\n", x); }
};


class B
{
    A a1;
    A a2;

public:
    B()
    :   a1(3),
        a2(5)
    {
        printf("B constructor\n");
        throw "failed";
    }
    ~B() { printf("B destructor\n"); }
};


int main()
{
    B b;

    return 0;
}

다음 출력으로 (G ++ 4.5.2 사용) :

A constructor [3]
A constructor [5]
B constructor
terminate called after throwing an instance of 'char const*'
Aborted

생성자가 파트 웨이에 실패하면이를 처리하는 것이 귀하의 책임입니다. 더 나쁜 것은, 기본 클래스의 생성자에서 예외가 발생할 수 있습니다! 이러한 사례를 다루는 방법은 "기능 시도 블록"을 사용하는 것입니다 (그러나 심지어 부분적으로 초기화 된 객체의 파괴를 신중하게 코딩해야합니다).

문제에 대한 올바른 접근 방식은 다음과 같습니다.

#include <stdio.h>


class A
{
    int x;

public:
    A(int x) : x(x) { printf("A constructor [%d]\n", x); }
    ~A() { printf("A destructor [%d]\n", x); }
};


class B
{
    A * a1;
    A * a2;

public:
    B()
    try  // <--- Notice this change
    :   a1(NULL),
        a2(NULL)
    {
        printf("B constructor\n");
        a1 = new A(3);
        throw "fail";
        a2 = new A(5);
    }
    catch ( ... ) {   // <--- Notice this change
        printf("B Cleanup\n");
        delete a2;  // It's ok if it's NULL.
        delete a1;  // It's ok if it's NULL.
    }

    ~B() { printf("B destructor\n"); }
};


int main()
{
    B b;

    return 0;
}

실행하면 할당 된 물체 만 파괴 및 해제되는 예상 출력을 얻게됩니다.

B constructor
A constructor [3]
B Cleanup
A destructor [3]
terminate called after throwing an instance of 'char const*'
Aborted

원하는 경우 스마트 공유 포인터를 사용하여 추가 복사를 할 수 있습니다. 이와 유사한 생성자 작성 :

class C
{
    std::shared_ptr<someclass> a1;
    std::shared_ptr<someclass> a2;

public:
    C()
    {
        std::shared_ptr<someclass> new_a1(new someclass());
        std::shared_ptr<someclass> new_a2(new someclass());

        // You will reach here only if both allocations succeeded. Exception will free them both since they were allocated as automatic variables on the stack.
        a1 = new_a1;
        a2 = new_a2;
    }
}

행운을 빕니다, tzvi.

생성자를 던지면 전화를 걸기 전에 온 모든 것을 정리해야합니다. 상속을 사용하거나 파괴자를 던지는 경우 실제로는 안됩니다. 동작은 홀수입니다 (표준은 편리하지 않지만 정의되지 않았을 수도 있습니까?).

예, 그 코드는 메모리 유출됩니다. "새"를 사용하여 할당 된 메모리 블록은 예외가 제기 될 때 해제되지 않습니다. 이것은 뒤에 동기 부여의 일부입니다 raii.

메모리 누출을 피하려면 다음과 같은 것을 시도하십시오.

psomeclass = NULL;
pint = NULL;
/* So on for any pointers you allocate */

try {
    objsomeclass = someclass();
    psomeclass = new someclass();
    pint = new int(); 
    throw "constructor failed";
    a = 43;
 }
 catch (...)
 {
     delete psomeclass;
     delete pint;
     throw;
 }

당신이 "새로운"모든 것을 삭제해야합니다. 그렇지 않으면 메모리 누출이 발생합니다. 그래서이 두 줄 :

psomeclass = new someclass();
pint = new int(); 

해야하기 때문에 메모리 누출이 발생합니다.

delete pint;
delete psomeclass;

그들이 유출되는 것을 피하기 위해 마침내 블록에서.

또한이 줄 :

base temp = base();

불필요합니다. 당신은 그냥해야합니다 :

base temp;

"= base ()"를 추가하면 불필요합니다.

psomeclass를 삭제해야합니다 ... 정수를 정리할 필요는 없습니다 ...

rwendi

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top