Pregunta

Yo tengo un class A que utiliza una asignación de memoria dinámica para uno de sus campos.La clase A se crea una instancia y se almacena como un campo de puntero en otra clase (class B.

Cuando termino con un objeto de clase B, llamo delete, que supongo llama al destructor...¿Pero esto también llama al destructor de clase A?

Editar:

De las respuestas, entiendo eso (edítelo si es incorrecto):

  1. delete de una instancia de B llama a B::~B();
  2. que llama A::~A();
  3. A::~A debería explícitamente delete todas las variables miembro asignadas al montón del objeto A;
  4. Finalmente, el bloque de memoria que almacena dicha instancia de clase B se devuelve al montón - cuando nuevo se usó, primero asignó un bloque de memoria en el montón, luego invocó a los constructores para inicializarlo, ahora, después de que se hayan invocado todos los destructores para finalizar el objeto, el bloque donde residía el objeto se devuelve al montón.
¿Fue útil?

Solución

El destructor de A se ejecutará cuando finalice su vida útil.Si desea liberar su memoria y ejecutar el destructor, debe eliminarlo si estaba asignado en el montón.Si se asignó en la pila, esto sucede automáticamente (es decir,cuando sale del alcance;ver RAII).Si es miembro de una clase (no un puntero, sino un miembro completo), esto sucederá cuando se destruya el objeto que lo contiene.

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

En el ejemplo anterior, se necesitan cada eliminación y eliminación [].Y no es necesario eliminarlo (ni tampoco se puede usar) donde no lo usé.

auto_ptr, unique_ptr y shared_ptr etc...son excelentes para hacer que esta gestión de por vida sea mucho más 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

Otros consejos

Cuando se llama a eliminar en un puntero asignado por el nuevo, el destructor del objeto apuntado, será llamado.

A * p = new A;

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

Se denomina "destructor", no "Deconstructor".

En el interior del destructor de cada clase, hay que eliminar todas las otras variables miembro que han sido asignados con uno nuevo.

Edit: Para aclarar:

Supongamos que tiene

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

La asignación de una instancia de B y luego la eliminación se limpia, porque lo que B asigna internamente también se eliminarán en el destructor.

Pero instancias de la clase C tendrán fugas de memoria, ya que asigna una instancia de A que no libera (en este caso C no tiene ni siquiera un destructor).

Si usted tiene un puntero habitual (A*), entonces no se llamará al destructor (y memoria para A instancia no será liberado tampoco) a menos que hagas delete explícitamente en destructor B 's. Si quieres ver la destrucción automática en punteros inteligentes como auto_ptr.

Debería eliminar Un mismo en el destructor 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;
    }
};

Al hacer:

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

El destructor será llamado sólo si su clase base tiene la palabra clave virtual.

A continuación, si no tiene un destructor virtual sólo ~ B () se llama. Pero ya que usted tiene un destructor virtual, primero ~ D () será llamado, entonces ~ B ().

No hay miembros de B o D asignada en el montón se cancela la asignación a menos que elimine explícitamente. Y borrarlos llamará a su destructor también.

Me preguntaba por qué mi clase destructor no fue llamado. La razón era que me había olvidado de incluir la definición de esa clase ( "class.h" # include). Yo sólo tenía una declaración como "clase A"; y el compilador estaba contento con él y dejar que me llaman "Borrar".

No. Se eliminará el puntero. Debe llamar a la de eliminación en un explícito en el destructor de B.

El destructor del objeto de clase A, solo será llamado si se llama de borrado para ese objeto. Asegúrese de eliminar ese puntero en el destructor de la clase B.

Para un poco más de información sobre lo que sucede cuando se elimina está llamado a un objeto, consulte: http://www.parashift.com/c++- faq-lite / almacén libre-mgmt.html # faq-16.9

No, no lo llamará destructor para la clase A, debe llamar explícitamente (como PoweRoy dijo), borrar la línea 'eliminar ptr;' en el ejemplo de 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;
  }

Usted tiene algo así como

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

Si a continuación, llama a delete b;, no pasa nada a una, y usted tiene una pérdida de memoria. Tratando de recordar a delete b->a; no es una buena solución, pero hay un par de los demás.

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

Este es un destructor de B que eliminar una. (Si a es 0, que elimine no hace nada. Si a no es 0, pero no apunta a la memoria de nuevo, se obtiene daños en la pila.)

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

De esta manera usted no tiene un como un puntero, sino más bien una auto_ptr <> (shared_ptr <> lo hará así, u otros punteros inteligentes), y se elimina automáticamente cuando b es.

Cualquiera de estas formas funciona bien, y yo he usado tanto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top