Pergunta

Eu tenho um class A que utiliza uma alocação de memória heap para um de seus campos. Classe A é instanciado e armazenado como um campo de ponteiro em outra classe (class B.

Quando eu sou feito com um objeto da classe B, eu chamo delete, que eu suponho que chama o destruidor ... Mas será que esta chamada o destruidor da classe A, bem como?

Editar:

A partir das respostas, eu levo isso (por favor edite se incorretas):

  1. delete de uma instância de B chama B :: ~ B ();
  2. que chama A::~A();
  3. A::~A deve delete explicitamente todas as variáveis ??de membro alocado-heap do objeto A;
  4. Finalmente o armazenamento bloco de memória disse instância da classe B é retornado para a pilha - quando new foi usado, ele alocados primeiramente um bloco de memória no montão, construtores, então invocadas para inicializar-lo, agora, depois de todos os destruidores têm sido invocadas para finalizar o objeto do bloco onde o objeto residia é retornado para a pilha.
Foi útil?

Solução

O destruidor de A será executado quando seu tempo de vida é longo. Se você quiser a sua memória para ser liberado e o destruidor executar, você tem que excluí-lo se ele foi alocado no heap. Se ele foi alocada na pilha isso acontece automaticamente (ou seja, quando se sai do escopo, ver RAII). Se for um membro de uma classe (não um ponteiro, mas um membro pleno), então isso vai acontecer quando o objeto que contém é destruída.

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

No exemplo acima, cada Apagar e Apagar [] é necessário. E não de exclusão é necessária (ou mesmo capaz de ser usado) onde eu não usá-lo.

auto_ptr, unique_ptr e shared_ptr etc ... são grandes para fazer essa gestão vida muito mais fácil:

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

Outras dicas

Quando você chama de exclusão em um ponteiro alocado pelo novo, o destruidor do objeto apontado será chamado.

A * p = new A;

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

É nomeado "destruidor", não "deconstructor".

Dentro do processo de destruição de cada classe, você tem que eliminar todas as outras variáveis ??de membro que foram alocados com nova.

Edit: Para esclarecer:

Digamos que você tenha

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;
}

A alocação de uma instância de B e, em seguida, apagar é limpo, porque o que aloca B internamente também serão excluídos no processo de destruição.

Mas as instâncias de classe C vai vazar memória, porque ele aloca uma instância de A, que não libera (neste caso C não tem sequer um destruidor).

Se você tem um ponteiro usual (A*), em seguida, o destruidor não será chamado (e memória, por exemplo A não serão liberados qualquer um) a menos que você faça delete explicitamente no processo de destruição de B. Se você quiser olhar automática destruição em ponteiros inteligentes como auto_ptr.

Você deve eliminar um a si mesmo no processo de destruição de B.

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;
    }
};

Quando você faz:

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

O destrutor será chamado apenas se a sua classe base tem a palavra-chave virtual.

Então, se você não só tem um destrutor virtual ~ B () seria chamado. Mas desde que você tem um destrutor virtual, primeiro ~ D () será chamado, então ~ B ().

Não há membros de B ou D alocados na pilha será desalocada a menos que você excluí-los explicitamente. E excluí-los vai chamar seu destruidor bem.

Eu queria saber por que destructor minha classe não foi chamado. A razão foi que eu tinha esqueceu de incluir definição dessa classe ( "class.h" #include). Eu só tinha uma declaração como "classe A"; eo compilador estava feliz com isso e deixe-me chamar de "excluir".

No. o ponteiro será apagado. Você deve chamar a exclusão em uma explícita no processo de destruição de B.

O destruidor para o objeto da classe A só será chamado se de exclusão é chamado para esse objeto. Certifique-se de excluir esse ponteiro no processo de destruição de classe B.

Para um pouco mais informações sobre o que acontece quando delete é chamado em um objeto, consulte: http://www.parashift.com/c++- faq-lite / freestore-mgmt.html # faq-16,9

Não, não vai chamar destrutor para a classe A, você deve chamá-lo de forma explícita (como PoweRoy disse), linha delete 'ptr de exclusão;' no exemplo para comparar ...

  #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;
  }

Você tem algo como

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

Se você, em seguida, chamar delete b;, nada acontece a um, e você tem um vazamento de memória. Tentando lembrar de delete b->a; não é uma boa solução, mas há um par de outros.

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

Este é um destruidor para B que irá eliminar a. (Se a é 0, que apagar nada faz. Se um não é 0, mas não aponta para a memória de novo, você tem corrupção de pilha.)

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

Desta forma, você não tem um como um ponteiro, mas sim um auto_ptr <> (shared_ptr <> vai fazer tão bem, ou outros ponteiros inteligentes), e ele é automaticamente excluído quando b é.

Qualquer uma destas formas funciona bem, e eu usei ambos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top