velocidad solo punteros puntero mueve mac loco lenovo laptop informatica funciona esta cambiar aparece c++ memory-leaks undefined-behavior

c++ - solo - puntero informatica



¿Por qué la eliminación de mi puntero elimina mi puntero? (8)

Entonces, para comprender mejor / eliminar mejor (realmente para probarme a mí mismo con pequeños ejemplos de por qué los destructores virtuales son necesarios para las interfaces), quiero entender las pérdidas de memoria, de modo que pueda vivir con miedo de ellos. Pero estoy teniendo dificultades para obtener mi fuga, por así decirlo; de hecho, estoy teniendo un momento difícil con el nuevo / eliminar también.

Aquí está mi versión más simple:

int* P1 = new int(43); cout<<"P1 = "<<P1<<endl; cout<<"*P1 = "<<*P1<<endl; delete P1; cout<<"P1 = "<<P1<<endl; cout<<"*P1 = "<<*P1<<endl;

Esto imprime:

P1 = 0xcc0340 *P1 = 43 P1 = 0xcc0340 *P1 = 43

Tenía algo más complicado dentro de una clase, pero este ejemplo ilustra mi falla. Pensé que eliminar toma un puntero y libera su memoria, lo que invalida el puntero o al menos lo que apunta? Debo estar haciendo algo muy simple muy mal.


Debo estar haciendo algo muy simple muy mal.

Estás absolutamente en lo correcto. Tu código está haciendo algo muy simple muy mal, y has pagado el precio máximo, sin ver ningún resultado negativo . A veces, haces las cosas mal, y no pasa nada malo. Este es el peor resultado posible, porque es posible que no se dé cuenta de que su código es incorrecto y continuará usándolo, hasta que un día su código se rompa inesperadamente y no tenga ni idea de dónde ni cómo, porque siempre ha funcionado. Se romperá en algún lugar completamente irrelevante para la parte real que está mal, y pasarás horas tratando de rastrearlo y descubrir por qué está roto.

Cuando haces las cosas mal, es un comportamiento indefinido. Eso significa que cualquier cosa puede pasar. En el mejor de los casos, el código se bloquea y segmenta y las luces parpadeantes se encienden y dicen "USTED ESTÁ USANDO LA MEMORIA LIBRE" y todo está muy claro. En el peor, los demonios salen volando de tu nariz . Pero justo por encima de eso, el segundo peor resultado posible es que todo parece funcionar como pretendías.


Desreferenciar un puntero eliminado es un comportamiento indefinido, como ya se explicó, es decir, estás haciendo algo mal. Los compiladores pueden ayudarlo a encontrar ese error al cambiar el valor del puntero a algún valor mágico que siempre hará que la desreferenciación del puntero falle y le puede dar una pista de que es porque se eliminó previamente.

Una prueba rápida mostró el siguiente comportamiento para mí:
MSVC2010:
creación de depuración: * P1 = 0xfeeefeee
lanzamiento de versión: * P1 = <aleatorio>
GCC 4.6:
versiones de depuración y liberación: * P1 = 0

Entonces tu eras (no) afortunado de que obtuvieras nuevamente el valor original. Te recomiendo que construyas siempre en modo de depuración para probar tus programas (incluso si no estás depurando) porque agrega verificaciones de cordura adicionales a tu código.


Eliminar no invalida el puntero. Libera la memoria a la que apunta de vuelta al montón. En este caso, la memoria no se ha reutilizado y, por lo tanto, aún contiene el mismo contenido. En algún momento, esa memoria SERÁ reutilizada y luego obtendrá el comportamiento indefinido del que otros hablan.

Aunque esto no es una pérdida de memoria. Es entonces cuando señala el puntero a otra asignación de memoria (o simplemente descarta el puntero) sin liberar la memoria a la que apunta. El primero permanece alojado y, como no tiene referencias, no tiene forma de liberarlo.


Estás causando un comportamiento indefinido . Esto significa que cualquier cosa puede suceder. Como algo sucedió realmente, todo se comporta como está documentado. (A veces, "algo" se ve muy similar a otra cosa que usted podría esperar erróneamente. Hacer exactamente lo que cree que estaba tratando de lograr es una de las posibles instancias permitidas de "comportamiento indefinido").

Tenga en cuenta también que una "fuga de memoria" es algo opuesto a lo que intenta hacer: en una pérdida de memoria, se olvida de liberar memoria, mientras que ya ha liberado la memoria y ahora está accediendo a la memoria no válida.

Aquí hay una pérdida de memoria real, que tampoco causa un comportamiento indefinido: ¡no confunda "mal pero correcto" con programación "incorrecta"!

int * factorial(int * n) { if (*n == 0) return new int(1); else return new int(*n * *factorial(*n - 1)); }


Este código

delete P1; cout<<"P1 = "<<P1<<endl; cout<<"*P1 = "<<*P1<<endl;

causa comportamiento indefinido. Entonces, cualquier cosa puede suceder. Es mucho más fácil causar una pérdida de memoria:

for(;;) new int;


Esto sería una pérdida de memoria:

int* P1 = new int(43); P1 = new int(42);

Asignando memoria sin borrarla de nuevo.


La memoria se libera pero no se limpia. El valor puede permanecer en la memoria hasta que otro proceso escriba un nuevo valor en esa ubicación.


// Reserve some memory for an int and set that memory to the value 43. int* P1 = new int(43); // Print the address of the reserved memory. cout<<"P1 = "<<P1<<endl; // Print the contents of that memory. cout<<"*P1 = "<<*P1<<endl; // Free the memory - it is no longer reserved to you. delete P1; // int* P2 = new int(47); // Print the address of the memory. It still holds the address to // the memory that used to be reserved for you. cout<<"P1 = "<<P1<<endl; // Print the current value of the memory that used to be reserved. cout<<"*P1 = "<<*P1<<endl;

Si quita el comentario de la línea P2, es bastante probable que se le asigne la misma memoria que cambiaría el valor impreso en la última línea.

El acceso a la memoria que se ha liberado con delete causa un comportamiento indefinido, como han señalado otros. Indefinido incluye colisiones de formas extrañas en algunos casos (¿solo durante la luna llena?). También incluye todo funcionando perfectamente bien por ahora, pero con el error de ser una mina que se puede disparar cada vez que realice otro cambio en cualquier otro lugar de su programa.

Un puentito de memoria es cuando asigna memoria con new y nunca la libera con delete . Esto normalmente no se notará hasta que alguien ejecute su programa por un período más largo y descubra que se come toda la memoria del sistema.