c++ - moz - seo image alt tag example
¿Se llama a un destructor cuando un objeto sale del alcance? (5)
En este caso, cuando el retorno principal es el final del programa, el sistema operativo se encargará de liberar todos los recursos. Si, por ejemplo, esta fuera cualquier otra función, tendría que usar eliminar.
Por ejemplo:
int main() {
Foo *leedle = new Foo();
return 0;
}
class Foo {
private:
somePointer* bar;
public:
Foo();
~Foo();
};
Foo::~Foo() {
delete bar;
}
¿Sería el destructor implícitamente llamado por el compilador o habría una pérdida de memoria?
Soy nuevo en la memoria dinámica, así que si este no es un caso de prueba utilizable, lo siento.
Primero tenga en cuenta que el código no se compilaría; new
devuelve un puntero a un objeto asignado en el montón. Necesitas:
int main() {
Foo *leedle = new Foo();
return 0;
}
Ahora, dado que new
asigna el objeto con almacenamiento dinámico en lugar de automático, no saldrá del alcance al final de la función. Por lo tanto, tampoco se borrará, y habrá filtrado la memoria.
Sí, las variables automáticas se destruirán al final del bloque de código adjunto. Pero sigue leyendo.
El título de su pregunta pregunta si se llamará a un destructor cuando la variable se salga del alcance. Presumiblemente, lo que quiso preguntar fue:
¿Se llamará al destructor de Foo al final de main ()?
Dado el código que proporcionó, la respuesta a esa pregunta es no, ya que el objeto Foo tiene una duración de almacenamiento dinámico, como veremos en breve.
Tenga en cuenta aquí lo que es la variable automática:
Foo* leedle = new Foo();
Aquí, leedle
es la variable automática que se destruirá. leedle
es solo un puntero. Lo que apunta a los puntos no tiene una duración de almacenamiento automática y no se destruirá. Entonces, si haces esto:
void DoIt()
{
Foo* leedle = new leedle;
}
Se filtra la memoria asignada por la new leedle
.
Debe delete
todo lo que se haya asignado con new
:
void DoIt()
{
Foo* leedle = new leedle;
delete leedle;
}
Esto se hace mucho más simple y más robusto mediante el uso de punteros inteligentes. En C ++ 03:
void DoIt()
{
std::auto_ptr <Foo> leedle (new Foo);
}
O en C ++ 11:
void DoIt()
{
std::unique_ptr <Foo> leedle = std::make_unique <Foo> ();
}
Los punteros inteligentes se utilizan como variables automáticas, como se indicó anteriormente, y cuando salen del alcance y se destruyen, delete
automáticamente (en el destructor) el objeto al que se apunta. Entonces, en los dos casos anteriores, no hay pérdida de memoria.
Tratemos de aclarar un poco el lenguaje aquí. En C ++, las variables tienen una duración de almacenamiento. En C ++ 03, hay 3 duraciones de almacenamiento:
1: automático : una variable con duración de almacenamiento automático se destruirá al final del bloque de código adjunto.
Considerar:
void Foo()
{
bool b = true;
{
int n = 42;
} // LINE 1
double d = 3.14;
} // LINE 2
En este ejemplo, todas las variables tienen una duración de almacenamiento automática. Tanto b
como d
se destruirán en la LÍNEA 2. n
se destruirán en la LÍNEA 1.
2: estático : una variable con una duración de almacenamiento estática se asignará antes de que comience el programa, y se destruirá cuando finalice el programa.
3: dinámico : una variable con duración de almacenamiento dinámica se asignará cuando la asigne utilizando funciones de asignación de memoria dinámica (por ejemplo, new
) y se destruirá cuando la destruya utilizando funciones de asignación de memoria dinámica (por ejemplo, delete
).
En mi ejemplo original anterior:
void DoIt()
{
Foo* leedle = new leedle;
}
leedle
es una variable con duración de almacenamiento automática y se destruirá en la llave final. Lo que apunta a la duración de almacenamiento dinámico no se destruye en el código anterior. Debe llamar a delete
para desasignarlo.
C ++ 11 también agrega una cuarta duración de almacenamiento:
4: subproceso : las variables con duración de almacenamiento de subprocesos se asignan cuando el subproceso comienza y se desasignan cuando termina el subproceso.
Sí, si un objeto sale del alcance, se llama al destructor. PERO No, no se llamará al destructor en este caso, porque solo tiene un puntero en el alcance, ese puntero no tiene un destructor particular, por lo que no habrá una llamada indirecta al destructor de Foo
.
Este ejemplo es el dominio de aplicación de punteros inteligentes como std::unique_ptr
y std::shared_ptr
. Esas son clases reales que, a diferencia de los punteros sin procesar, tienen un destructor, (condicionalmente) que llama a delete
en el objeto señalado.
Por cierto, la bar
eliminación de destructor de Foo
no se ha inicializado ni asignado a una dirección que apunta a un objeto real, por lo que la llamada de eliminación dará un comportamiento indefinido, probablemente un bloqueo.
habría una pérdida de memoria de hecho. Se llama al destructor del objeto que sale del alcance (el Foo *), pero no al del objeto apuntado (el Foo que asignó).
Técnicamente hablando, dado que usted es el principal, no se trata de una pérdida de memoria, ya que hasta cuando la aplicación no finaliza puede acceder a cada variable asignada. Con respecto a esto, cito Alexandrescu (de Modern C ++, el capítulo sobre singletons)
Las pérdidas de memoria aparecen cuando asigna datos que se acumulan y pierde todas las referencias al mismo. Este no es el caso aquí: nada se está acumulando y mantenemos el conocimiento sobre la memoria asignada hasta el final de la aplicación. Además, todos los modernos
Por supuesto, esto no implica que no deba llamar a delete
, ya que sería una práctica extremadamente mala (y peligrosa).