2012-01-31 24 views
5
# include <iostream> 

int main() 
{ 
using std::cout; 
int *p= new int; 

*p = 10; 
cout<<*p<<"\t"<<p<<"\n"; 
delete p; 
cout<<*p<<"\t"<<p<<"\n"; 

return 0; 

} 

Salida:
10 0x237c010
0 0x237c010¿'borrar puntero' significa simplemente '* puntero = 0'?

Aquí, después de borrar p, ¿por qué el puntero p conserva su valor? No borrar libera el puntero p?
¿Qué significa exactamente 'liberar el puntero'?
significa 'eliminar p' significa simplemente '* p = 0'? (Lo que parece desde la salida)

+0

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

+2

Usa un poco de pensamiento crítico: ¿cómo funcionaría '* p = 0' incluso para, p. 'std :: string'? – ildjarn

Respuesta

6

Aquí, después de borrar p, ¿por qué el puntero p conserva su valor?

Así es como está diseñado el idioma. Si desea que el puntero que sostenga se ponga a cero, tendrá que asignarlo cero usted mismo. El puntero p es otra pieza de memoria, separada de la asignación/objeto a la que apunta.

No borrar libera el puntero p?

Llama al destructor el objeto y devuelve la memoria al sistema (como libre). Si se trata de una matriz (delete[]), se invocarán destructores para todos los elementos, luego se devolverá la memoria.

¿Qué significa exactamente 'liberar el puntero'?

Cuando quiere una pieza de memoria del sistema, la asigna (por ejemplo, usando new). Cuando haya terminado de usarlo, lo devuelve utilizando la llamada gratuita/eliminar correspondiente. Es un recurso, que debes devolver. Si no lo hace, su programa se fugará (y nadie lo quiere).

+0

@ Justin- ¿Podría explicar por qué el puntero p ha conservado su valor en el código anterior incluso después de eliminarlo? –

+3

@Avinash: ¿Por qué la desasignación de memoria cambia su contenido? – ildjarn

+0

@AvinashSonawane expandido – justin

0

delete p simplemente libera la memoria asignada durante una llamada al operador new. No cambia el valor del puntero o el contenido de la memoria desasignada.

+0

'delete' asegura que se llama al destructor, lo que puede cambiar el valor del puntero o el contenido de la memoria desasignada. –

+0

@ Narrakan- Si no hay cambio en el valor del puntero ni en el valor apuntado, ¿qué se consigue exactamente liberando la memoria? Como el valor del puntero no se cambia, cualquiera puede acceder simplemente a ese objeto 'eliminado'. –

+0

@AvinashSonawane, como lo ha visto usted mismo, puede acceder a '* p' incluso después de' borrar'd, por lo que aún puede acceder a esa memoria, aunque es un comportamiento indefinido. –

1

Aquí después de eliminar p, ¿por qué el puntero p conserva su valor? No borrar libera el puntero p?

Libera la memoria a la que apunta el puntero (después de llamar a cualquier destructor apropiado). El valor del puntero en sí no se modifica.

¿Qué significa exactamente 'liberar el puntero'?

Como se indica anteriormente, significa liberar la memoria a la que apunta el puntero.

Does eliminar p 'significa simplemente '* p = 0'? (Lo que parece desde la salida)

No. El sistema no tiene a escribir nada en la memoria que es liberado, y si escribe algo, no tiene que escribir 0. Sin embargo, el sistema generalmente tiene que administrar esa memoria de alguna manera, y eso podría escribir en el área de memoria a la que apuntaba el puntero.Además, la memoria recién liberada se puede asignar a otra cosa (y en una aplicación de subprocesos múltiples, eso podría suceder antes de que la operación delete incluso vuelva). El nuevo propietario de ese bloque de memoria puede, por supuesto, escribir lo que quiera en esa memoria.

Un puntero que apunta a un bloque de memoria liberado a menudo se conoce como un puntero 'colgando'. Es un error desreferenciar un puntero colgante (para lectura o escritura). A veces verá el código asignar inmediatamente un NULL o 0 a un puntero inmediatamente después de eliminar el puntero, a veces utilizando una macro o plantilla de función que borra y elimina el puntero. Tenga en cuenta que esto no solucionará todos los errores con punteros colgantes, ya que otros punteros pueden haber sido configurados para apuntar al bloque de memoria.

El método moderno para tratar con este tipo de problemas es evitar el uso de punteros sin procesar a favor del uso de punteros inteligentes como shared_ptr o unique_ptr.

0

(Tenga en cuenta la siguiente no es cómo funciona realmente lo que tomar con un grano de sal.)

Dentro de la aplicación de la nueva Mantiene una lista de toda la memoria disponible cuando dijiste "int * p = nuevo int; cortó un bloque de tamaño interno de su lista de memoria disponible y se lo dio. Cuando ejecuta "eliminar p"; se vuelve a poner en la lista de memoria disponible. Si su programa llama nuevo 30 veces sin llamar a eliminar, obtendrá 30 fragmentos diferentes de tamaño nuevo. Si llamaste nuevo y luego borraste 30 veces seguidas, podrías (pero no necesariamente) obtener el mismo bloque de tamaño int. Esto se debe a que dijiste que ya no la estabas utilizando cuando llamaste a eliminar y, por lo tanto, era nuevo para reutilizarlo.

TLDR; Eliminar notifica que esta sección de la memoria está disponible nuevamente y que no toca su variable.

2

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 *ppodrí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".