Para comprender qué significa la memoria de liberación, primero debe comprender qué significa que asigna la memoria. Lo que sigue es una explicación simplificada.
Existe memoria. La memoria es una gran cantidad de cosas a las que puedes acceder. Pero dado que es global, necesita alguna forma de dividirlo. Una forma de gobernar quién puede acceder a qué piezas de memoria. Uno de los sistemas que rige la distribución de la memoria se llama "montón".
El montón posee una cierta cantidad de memoria (algunos son propiedad de la pila y otros son propiedad de datos estáticos, pero no importa eso ahora). Al comienzo de su programa, el montón dice que no tiene acceso a ninguna memoria que pertenezca al heap.
Lo que new int
hace es dos veces. Primero, va al sistema Heap y dice: "Quiero una memoria adecuada para almacenar un int
en". Obtiene un puntero exactamente a eso: una parte del montón, en la que puede de forma segura almacenar y recuperar exactamente un valor de tipo int
.
Ahora es el orgulloso propietario de la memoria de int
. El montón garantiza que mientras se sigan sus reglas, lo que sea que coloque allí se conservará hasta que lo modifique explícitamente. Este es el pacto entre usted y el montón omnipotente.
Lo otro new int
hace es inicializar esa parte del montón con un valor de int
. En este caso, se inicializa por defecto, porque no se pasó ningún valor (new int(5)
lo inicializaría con el valor 5).
De ahora en adelante, está legalmente permitido almacenar exactamente un int
en este pedazo de memoria. Puede recuperar el int
almacenado allí. Y se te permite hacer otra cosa: decirle al montón que has terminado de usar esa memoria.
Cuando llama al delete p
, suceden dos cosas. Primero, p
está desinicializado. Nuevamente, como es un int
, no ocurre nada. Si esto fuera una clase, su destructor sería llamado.
Pero después de eso, delete
sale al montón y dice: "Oye montón: ¿recuerdas este puntero a un int
que me diste? Ya terminé con eso". El sistema de montón puede hacer lo que quiera. Tal vez borrará la memoria, como algunos montones en depuración-compilaciones. Sin embargo, en versiones de lanzamiento, la memoria puede no borrarse.
Por supuesto, la razón por la que el montón puede hacer lo que quiera es porque, el momento borra ese puntero, usted entra en un nuevo acuerdo con el montón. Anteriormente, pediste una pieza de memoria para int
, y el montón estaba obligado. Usted era dueño de ese recuerdo, y el montón le garantizaba que era suyo todo el tiempo que quisiera. Las cosas que coloques allí permanecerían allí.
Después de que se divirtió, lo devolvió al montón. . Y aquí es donde entra en juego el contrato Cuando dice delete p
, por cualquier objeto p
, que dice lo siguiente:
Juro solemnemente no tocar esta dirección de memoria de nuevo!
Ahora, el montón podría devolverte esa dirección de memoria si llamas de nuevo al new int
. Puede darte una diferente. Pero solo tiene acceso a la memoria asignada por el montón durante el tiempo entrenew
y delete
.
Teniendo en cuenta esto, ¿qué significa esto?
delete p;
cout << *p << "\t" << p << "\n";
En lenguaje C++, esto se denomina "comportamiento indefinido". La especificación C++ tiene muchas cosas que se dice que son "indefinidas". Cuando activa un comportamiento indefinido puede pasar cualquier cosa.*p
podría ser 0. *p
podría ser el valor que solía ser. Haciendo *p
podría bloquear su programa.
La especificación C++ es un contrato entre usted y su compilador/computadora. Dice lo que puedes hacer y dice cómo responde el sistema. "Comportamiento indefinido" es lo que ocurre cuando rompe el contrato, cuando hace algo que la especificación C++ dice que no debe. En ese punto, cualquier cosa puede suceder.
Cuando llamó al delete p
, le dijo al sistema que estaba terminado usando p
. Utilizándolo nuevamente, estaba mintiendo en el sistema. Y, por lo tanto, el sistema ya no tiene que cumplir ninguna regla, como almacenar los valores que desea almacenar. O continuar corriendo O no desovando demonios de tu nariz. O lo que sea.
Usted ha infringido las reglas. Y debes sufrir las consecuencias.
Así que no, delete p
no es el equivalente a *p = 0
. Esto último simplemente significa "establecer 0 en la memoria apuntada por p
". Lo primero significa "Terminé de usar la memoria apuntada por p
, y no la volveré a usar hasta que me diga que puedo".
Bueno, al menos también elimina los datos apuntados por el puntero, pero estoy seguro de que alguien tendrá una respuesta mucho mejor en breve sobre lo que realmente significa "borrar" la memoria. Sospecho que ni siquiera puede poner a cero la memoria, sino que simplemente permite que ese espacio se asigne nuevamente. – prelic
Usa un poco de pensamiento crítico: ¿cómo funcionaría '* p = 0' incluso para, p. 'std :: string'? – ildjarn