서브 클래스에 대한 포인터에서 delete가 기본 클래스 소멸자를 호출합니까?


165

나는이 class A해당 필드 중 하나에 대한 힙 메모리 할당을 사용하는합니다. 클래스 A는 인스턴스화되어 다른 클래스 ( class B.

클래스 B의 객체로 작업을 마치면 delete소멸자를 호출한다고 가정합니다. 그러나 이것이 클래스 A의 소멸자를 호출합니까?

편집하다:

답변에서 나는 그것을 취합니다 (잘못된 경우 편집하십시오).

  1. delete B의 인스턴스 중 B :: ~ B ();
  2. 어떤 전화 A::~A();
  3. A::~A deleteA 객체의 모든 힙 할당 멤버 변수를 명시 적으로 지정 해야 합니다.
  4. 마지막으로 클래스 B의 해당 인스턴스를 저장하는 메모리 블록은 힙으로 반환됩니다. new 가 사용될 때 먼저 힙에 메모리 블록을 할당 한 다음 생성자를 호출하여 초기화했습니다. 이제 모든 소멸자가 호출되어 객체를 마무리 한 후 객체가있는 블록은 힙으로 반환됩니다.

답변:


183

수명이 끝나면 A의 소멸자가 실행됩니다. 메모리를 비우고 소멸자를 실행하려면 힙에 할당 된 메모리를 삭제해야합니다. 스택에 할당 된 경우 자동으로 발생합니다 (예 : 범위를 벗어난 경우 RAII 참조). 클래스의 멤버 (포인터가 아니라 전체 멤버)이면 포함하는 객체가 소멸 될 때 발생합니다.

class A
{
    char *someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { delete[] someHeapMemory; }
};

class B
{
    A* APtr;
public:
    B() : APtr(new A()) {}
    ~B() { delete APtr; }
};

class C
{
    A Amember;
public:
    C() : Amember() {}
    ~C() {} // A is freed / destructed automatically.
};

int main()
{
    B* BPtr = new B();
    delete BPtr; // Calls ~B() which calls ~A() 
    C *CPtr = new C();
    delete CPtr;
    B b;
    C c;
} // b and c are freed/destructed automatically

위의 예에서 모든 삭제 및 삭제 []가 필요합니다. 그리고 내가 그것을 사용하지 않은 곳에서는 삭제가 필요하지 않습니다 (또는 실제로 사용할 수 있습니다).

auto_ptr, unique_ptrshared_ptr등 ... 훨씬 쉽게이 수명 관리를 만들기위한 훌륭한 있습니다 :

class A
{
    shared_array<char> someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { } // someHeapMemory is delete[]d automatically
};

class B
{
    shared_ptr<A> APtr;
public:
    B() : APtr(new A()) {}
    ~B() {  } // APtr is deleted automatically
};

int main()
{
    shared_ptr<B> BPtr = new B();
} // BPtr is deleted automatically

메모리를 부분적으로 만 해제 할 때 소멸자가 호출되는지 궁금합니다 (예 : 잘못된 포인터 사용)
Tomáš Zato-Reinstate Monica

포인터는 숫자 일뿐입니다. 실수로 ++연산자를 사용할 수도 있습니다 . 따라서 클래스 데이터 중간을 가리키는 포인터가 여전히 효과가 있는지 궁금합니다.
Tomáš Zato-Reinstate Monica

2
@ TomášZato : 임의의 포인터로 delete를 호출하면 문제가 생깁니다. 그렇게 할 이유가 없습니다. 실제로 스마트 포인터 소멸자가 아닌 다른 곳에서 수동으로 delete를 호출하는 경우 스마트 포인터 또는 다른 객체 관리자를 사용하지 않는 이유를 다시 살펴보고 싶을 것입니다.
Eclipse

shared_array는 부스트 전용입니다.
Dronz

30

new가 할당 한 포인터에서 delete를 호출하면 지정된 객체의 소멸자가 호출됩니다.

A * p = new A;

delete p;    // A:~A() called for you on obkect pointed to by p

22

이름은 "소멸자"가 아니라 "소멸자"입니다.

각 클래스의 소멸자 내에서 new로 할당 된 다른 모든 멤버 변수를 삭제해야합니다.

편집 : 명확하게 :

당신이 가지고 있다고

struct A {}

class B {
    A *a;
public:
    B () : a (new A) {}
    ~B() { delete a; }
};

class C {
    A *a;
public:
    C () : a (new A) {}        
};

int main () {
    delete new B;
    delete new C;
}

B의 인스턴스를 할당 한 다음 삭제하는 것은 깨끗합니다. B가 내부적으로 할당 한 것은 소멸자에서도 삭제되기 때문입니다.

그러나 클래스 C의 인스턴스는 해제되지 않은 A의 인스턴스를 할당하기 때문에 메모리가 누출됩니다 (이 경우 C에는 소멸자도 없음).


5

일반적인 포인터 ( A*) 가 있으면 소멸자 에서 명시 적으로 지정 A하지 않으면 소멸자가 호출되지 않습니다 ( 예 : 메모리 도 해제되지 않음) . 자동 파괴를 원하면 같은 스마트 포인터를보십시오 .deleteBauto_ptr


4

B의 소멸자에서 A를 직접 삭제해야합니다.


4
class B
{
public:
    B()
    {
       p = new int[1024];  
    }
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
        //p will not be deleted EVER unless you do it manually.
    }
    int *p;
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

할 때 :

B *pD = new D();
delete pD;

기본 클래스에 virtual 키워드가있는 경우에만 소멸자가 호출됩니다.

그런 다음 가상 소멸자가 없으면 ~ B () 만 호출됩니다. 그러나 가상 소멸자가 있으므로 먼저 ~ D ()를 호출 한 다음 ~ B ()를 호출합니다.

명시 적으로 삭제하지 않으면 힙에 할당 된 B 또는 D의 구성원이 할당 해제되지 않습니다. 삭제하면 소멸자도 호출됩니다.


1

당신은 같은 것을 가지고

class B
{
   A * a;
}
B * b = new B;
b->a = new A;

그런 다음을 호출 delete b;하면 아무 일도 일어나지 않으며 메모리 누수가 발생합니다. 기억하려고하는 delete b->a;것은 좋은 해결책은 아니지만 몇 가지가 있습니다.

B::~B() {delete a;}

이것은 a를 삭제하는 B의 소멸자입니다. a가 0이면 해당 삭제는 아무 것도 수행하지 않습니다. a가 0이 아니지만 새 메모리를 가리 키지 않으면 힙 손상이 발생합니다.

auto_ptr<A> a;
...
b->a.reset(new A);

이렇게하면 a 포인터가 아닌 auto_ptr <> (shared_ptr <> 또는 다른 스마트 포인터)이되고 b가되면 자동으로 삭제됩니다.

이 방법 중 하나가 잘 작동하며 두 가지를 모두 사용했습니다.


1

왜 내 클래스의 소멸자가 호출되지 않았는지 궁금했습니다. 그 이유는 해당 클래스의 정의를 포함하는 것을 잊었 기 때문입니다 (#include "class.h"). 나는 "class A;"와 같은 선언 만했다. 그리고 컴파일러는 그것에 만족했고 "삭제"라고 부르겠습니다.


컴파일러 경고 레벨 증가
Phil1970

0

아니요. 포인터가 삭제됩니다. B의 소멸자에서 A에 대한 삭제를 명시 적으로 호출해야합니다.


나는 이것을하고 있는데, 내 질문은 소멸 자라는 것입니까?
Nick Bolton


0

아니요 A 클래스의 소멸자를 호출하지 않습니다. PoweRoy와 같이 명시 적으로 호출해야합니다 .'delete ptr; '행을 삭제하십시오. 예를 들어 비교 ...

  #include <iostream>

  class A
  {
     public:
        A(){};
        ~A();
  };

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

  class B
  {
     public:
        B(){ptr = new A();};
        ~B();
     private:
        A* ptr;
  };

  B::~B()
  {
     delete ptr;
     std::cout << "Destructor of B" << std::endl;
  }

  int main()
  {
     B* b = new B();
     delete b;
     return 0;
  }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.