Dudas con destructor
Frecuentes
Visto 106 equipos
1
Supongamos que tengo una clase:
class ClassX{
private:
int* p;
int i;
....
}
Y en algún lugar hago:
ClassX x;
.....
//and in a friend function or in a ClassX function
p = (int*) malloc (.....);
Entonces cuando x
salir de su alcance una vez que se invoque el destructor; pero no libera la memoria asignada por el malloc
¿derecho?
Y si lo redefino:
ClassX::~ClassX(){ delete [] p; }
libera la memoria asignada por el malloc
pero no la memoria asignada para los campos de la clase (es decir, i
y p
)?
¿Me estoy perdiendo algo?
Gracias por su atención.
6 Respuestas
3
En primer lugar, recuerda estas cosas:
- Cosas asignadas por
malloc
necesita ser desasignado porfree
- No use
malloc
- Cosas asignadas por
new
debe ser desasignado pordelete
- Cosas asignadas por
new[]
debe ser desasignado pordelete[]
- Uno
delete
para cadanew
y unodelete[]
para cadanew[]
- No uses ninguno de los anteriores.
Entonces, tiene razón al pensar que, sin un destructor, la memoria asignada por malloc
no será liberado. Si sigue las reglas anteriores, entonces necesita usar free
(no delete[]
) para desasignarlo:
ClassX::~ClassX() { free(p); }
Sin embargo, no deberías usar malloc
en C ++ en primer lugar, ya que no llama a los constructores de objetos, debe usar new
:
ClassX::ClassX() : p(new int) { }
// NOW we use delete since we used new (not delete[] since we didn't use new[])
ClassX::~ClassX() { delete p; }
Sin embargo, si hace eso, debe escribir un constructor de copia, un operador de asignación de copia, un constructor de movimiento y un operador de asignación de movimiento. Así que echemos un vistazo a una manera aún mejor:
class ClassX{
private:
ClassX();
std::unique_ptr<int> p;
int i;
....
};
// we have to break rule #6 here
ClassX::ClassX() : p(new int) { }
Ahora ni siquiera tiene que escribir un destructor, puede dejar que el puntero inteligente se ocupe de él porque llamará automáticamente delete
en lo que hiciste con new
cuando se llama a su destructor. Lo que nos lleva a...
Tu otra pregunta:
¿libera la memoria asignada por el malloc pero no la memoria asignada para los campos de la clase (es decir, iyp)?
Eso es aproximadamente 1/4 correcto. Como i
y p
son miembros de la clase, se desasignan automáticamente cuando se desasigna la clase envolvente y, si fueran clases en sí mismas, se llamaría a sus destructores. Así que si pones delete
en su destructor, que se encarga de la memoria asignada por new
y i
y p
se limpian automáticamente y todo está bien. (Solo acertó 1/4 porque usó la función de desasignación incorrecta).
Esto significa que, si usa un puntero inteligente, se llamará al destructor del puntero inteligente cuando se destruya su objeto, y desasignará automáticamente lo que asignó con new
para ti. Así que ni siquiera tienes que preocuparte por eso.
Todo esto es asumiendo que Realmente quiero tener una dinamica int
como parte de tu clase. Sin embargo, si puede, preferiría guardar el int
por valor (no almacenar un puntero en él) y de esa manera no tiene que meterse con punteros inteligentes, desasignación o cualquier otra cosa.
contestado el 03 de mayo de 12 a las 16:05
Gracias por tu clara respuesta. Tengo otra pregunta: usted escribió "se desasignan automáticamente cuando se desasigna la clase adjunta". Entonces, la desasignación de la clase envolvente no la realiza el destructor de clases, ¿verdad? - aslan986
@ Aslan986 eso es absolutamente correcto. Lo hace la persona que llama; si lo asignaron con new
, ellos debe desasignarlo con delete
. Si lo asignaron en la pila, el compilador lo desasigna automáticamente cuando sale del alcance. El destructor de la clase solo está destinado a desasignar cosas que se asignaron dinámicamente (con new
or new[]
). Y después de llamar al destructor de la clase, se llaman los destructores de todos los miembros. Luego, toda la clase se desasigna (como dije anteriormente, con delete
o automáticamente por el compilador). Y todo eso se hace automáticamente. - Seth Carnegie
3
La regla simple es: por cada malloc
debe haber exactamente uno free
; para cada new
, debe haber exactamente uno delete
; para cada new[]
debe haber exactamente uno delete[]
.
Para responder a sus preguntas:
[el destructor] no libera la memoria asignada por el malloc, ¿verdad?
Correcto. No es asi. En ese caso, ha invocado malloc
, pero nunca free
.
[el destructor modificado] libera la memoria asignada por el malloc pero no la memoria asignada para los campos de la clase?
Incorrecto. No libera la memoria (debes usar free
no, delete[]
en este caso. free
is malloc
socio de s. delete[]
is new[]
socio de No puedes cambiar de pareja.)
También es incorrecto, libera la memoria asignada para los campos de la clase (suponiendo que los campos no sean tipos de puntero). Se libera la memoria ocupada por un objeto. después de el destructor regresa.
¿Me estoy perdiendo algo?
Si va a utilizar punteros en bruto, también necesita comprender el Regla de tres. Pero, mejor aún, nunca uses punteros en bruto. Utilizar una puntero inteligente o un envase.
contestado el 23 de mayo de 17 a las 13:05
1
Tiene razón en que su destructor debería liberar p, pero si asigna con malloc
deberías liberar la memoria con free
. Alternativamente, puede asignar la memoria con:
x.p = new int[size];
Esto significaría que su delete[] p
; destructor sería correcto.
Con respecto a las variables miembro de la clase, no necesita preocuparse por eliminarlas, si su objeto se asignó en la pila, se eliminarán cuando la pila se relaje. Si su clase se asignó en el montón, se eliminarán cuando delete x;
. De cualquier manera, su tiempo de vida está vinculado al objeto que los contiene.
contestado el 03 de mayo de 12 a las 16:05
1
Las reglas son simples:
- Una memoria asignada con
new
debe ser liberado condelete
. - Una memoria asignada con
new []
debe ser liberado condelete []
. - Una memoria asignada con
malloc()
debe ser liberado confree()
.
Tenga en cuenta que debe pasar exactamente la misma dirección devuelta por las funciones de asignación a las funciones de desasignación.
Buenas practicas:
- Siempre es una buena práctica evitar las asignaciones dinámicas a menos que realmente las necesite.
- Si es necesario, debe usar algún tipo de puntero inteligente que se adapte a sus requisitos, la decisión de qué puntero inteligente usar depende de la propiedad y la semántica de por vida involucrada.
- En C ++, es raro que uno necesite usar
malloc
yfree
y no los use a menos que tenga buenas razones para hacerlo,
Además, en su caso, también debe seguir las Regla de tres para que su programa funcione correctamente.
contestado el 23 de mayo de 17 a las 13:05
1
Si asigna memoria manualmente, debe liberarla, no se libera automáticamente para usted.
Si llamas malloc
(o calloc
o realloc
) necesitas free
ese recuerdo Del mismo modo, si Ud. new
algo delete
eso y new[]
debe coincidir con delete[]
.
Dicho esto, está programando en C++ y rara vez hay una buena razón para administrar la memoria manualmente. Hacer uso de punteros inteligentes, std :: shared_ptr para propiedad compartida y std :: unique_ptr de otra manera.
Entonces tu clase se ve así:
#include <memory>
class ClassX{
private:
std::unique_ptr<int> p;
int i;
....
};
ClassX::ClassX() : p( new int ) {} /* No need to deallocate p manually */
Tenga en cuenta que unique_ptr
también tiene una especialización parcial para arreglos, así que si p
apunta a una matriz, puede asignar memoria de la siguiente manera:
class ClassX{
private:
std::unique_ptr<int[]> p;
int i;
....
};
Class::ClassX() : p ( new int[10] ) {}
También puede olvidarse por completo de tratar con punteros y usar std::vector
or std::array
, especialmente para algo simple como una matriz de enteros.
contestado el 03 de mayo de 12 a las 16:05
Sin embargo, si usa new[]
a unique_ptr
, el tipo debe ser std::unique_ptr<int[]>
no, std::unique_ptr<int>
. - Seth Carnegie
1
Para simplificar, siempre me digo a mí mismo que un puntero ES solo un número entero. (puede ser de 16, 32 o 64 bits dependiendo del sistema). Es un entero especial que ayuda a definir una dirección, pero es solo un numero entero.
Entonces, cuando construyes la clase X, asigna el espacio para dos 'enteros'. Uno llamado p, el otro llamado i. Y cuando se destruye la clase desasigna el espacio de dos enteros y algunas cosas.
Al destructor no le importa lo que hayas hecho con el valor del entero especial p (que representa una dirección). Podrías haber creado memoria como lo hiciste, o crear un número aleatorio: todo es lo mismo en la memoria que representa la clase X: solo un número entero.
contestado el 03 de mayo de 12 a las 16:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c++ or haz tu propia pregunta.
Haga coincidir malloc() con free() y new[] con delete[] - acraig5075
Mejor aún, no use malloc/free en código C++. Y aprenda sobre RAII y punteros inteligentes lo antes posible. - Steve Townsend