c++ - poo - ¿Borrar llama al destructor?
how to use a destructor c++ (11)
Tengo una clase (A) que usa una asignación de memoria de montón para uno de sus campos. La clase A se instancia y se almacena como un campo de puntero en otra clase (B).
Cuando termino con el objeto B, llamo a delete, que supongo que llama al destructor ... Pero, ¿esto también llama al destructor en la clase A?
Editar:
De las respuestas, lo tomo (edite si es incorrecto):
-
delete
instancia de B llama a B :: ~ B (); - que llama
A::~A();
-
and A::~A
debedelete
explícitamente todas las variables de miembro asignadas en el montón de A; - y finalmente el bloque de memoria que almacena dicha instancia de B se devuelve al montón; cuando se usó nuevo , primero asignó un bloque de memoria en el montón, luego invocó a los constructores para inicializarlo, ahora después de que se han invocado todos los destructores para finalizar el objeto el bloque donde residía el objeto se devuelve al montón.
Cuando llama a delete en un puntero asignado por nuevo, se llamará al destructor del objeto señalado.
A * p = new A;
delete p; // A:~A() called for you on obkect pointed to by p
Deberías eliminar A ti mismo en el destructor de B.
El destructor de A se ejecutará cuando termine su tiempo de vida. Si desea liberar su memoria y ejecutar el destructor, debe eliminarlo si se asignó en el montón. Si se asignó en la pila, esto sucede automáticamente (es decir, cuando se sale del alcance, vea 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, cada eliminación y eliminación [] es necesaria. Y no se necesita eliminar (o de hecho 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
El destructor para el objeto de la clase A solo se invocará si se llama a la eliminación para ese objeto. Asegúrese de eliminar ese puntero en el destructor de clase B.
Para obtener un poco más de información sobre qué sucede cuando se invoca delete en un objeto, consulte: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9
Me preguntaba por qué no se llamó al destructor de mi clase. La razón fue que olvidé incluir la definición de esa clase (#include "class.h"). Solo tuve una declaración como "clase A"; y el compilador estaba contento con él y me dejó llamar "eliminar".
No. el puntero será eliminado. Debería llamar a delete en A explicit en el destructor de B.
Se llama "destructor", no "deconstructor".
Dentro del destructor de cada clase, debe eliminar todas las demás variables miembro que hayan sido asignadas con nuevas.
editar: Para aclarar:
Digamos que tienes
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;
}
Asignar una instancia de B y luego eliminar está limpio, porque lo que B asigna internamente también se eliminará en el destructor.
Pero las instancias de clase C perderán memoria porque asigna una instancia de A que no libera (en este caso, C ni siquiera tiene un destructor).
Si tiene un puntero habitual ( A*
), no se llamará al destructor (y la memoria para la instancia A
tampoco se liberará), a menos que lo delete
explícitamente en el destructor de B
Si desea destrucción automática, mire los punteros inteligentes como auto_ptr
.
Tienes algo como
class B
{
A * a;
}
B * b = new B;
b->a = new A;
Si luego llama a delete b;
, nada le sucede a a, y tienes una pérdida de memoria. Tratando de recordar delete b->a;
no es una buena solución, pero hay un par de otros.
B::~B() {delete a;}
Este es un destructor para B que eliminará a. (Si a es 0, esa eliminación no hace nada. Si a no es 0, pero no apunta a la memoria de nuevo, obtienes corrupción de pila).
auto_ptr<A> a;
...
b->a.reset(new A);
De esta forma, no tendrá un puntero como, sino que un auto_ptr <> (shared_ptr <> también lo hará, u otros punteros inteligentes), y se eliminará automáticamente cuando b sea.
Cualquiera de estas formas funciona bien, y he usado ambas.
no, no llamará a destructor para la clase A, debería llamarlo explícitamente (como dijo PoweRoy), eliminar la línea ''eliminar ptr''; en el ejemplo 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;
}
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;
}
};
Cuando tu lo hagas:
B *pD = new D();
delete pD;
Se llamará al destructor solo si su clase base tiene la palabra clave virtual.
Entonces, si no tiene un destructor virtual, solo se invocará ~ B (). Pero como tiene un destructor virtual, primero se llamará ~ D (), luego ~ B ().
Ningún miembro de B o D asignado en el montón será desasignado a menos que los elimine explícitamente. Y borrarlos llamará a su destructor también.