Contexto: Estoy tratando de entender los consejos, los vimos hace un par de semanas en la escuela y mientras practicaba hoy me encontré con un tonto problema, puede ser muy sencillo para usted, pero tengo poca o ninguna experiencia en programación.
He visto bastantes preguntas en SO sobre la eliminación de punteros, pero todas parecen estar relacionadas con la eliminación de una clase y no con un puntero 'simple' (o cualquiera que sea el término correcto), aquí está el código que estoy tratando de correr:
#include <iostream>;
using namespace std;
int main() {
int myVar,
*myPointer;
myVar = 8;
myPointer = &myVar;
cout << "delete-ing pointers " << endl;
cout << "Memory address: " << myPointer << endl;
// Seems I can't *just* delete it, as it triggers an error
delete myPointer;
cout << "myPointer: " << myPointer << endl;
// Error: a.out(14399) malloc: *** error for object 0x7fff61e537f4:
// pointer being freed was not allocated
// *** set a breakpoint in malloc_error_break to debug
// Abort trap: 6
// Using the new keyword befor deleting it works, but
// does it really frees up the space?
myPointer = new int;
delete myPointer;
cout << "myPointer: " << myPointer << endl;
// myPointer continues to store a memory address.
// Using NULL before deleting it, seems to work.
myPointer = NULL;
delete myPointer;
cout << "myPointer: " << myPointer << endl;
// myPointer returns 0.
}
Entonces mis preguntas son:
- ¿Por qué no funciona el primer caso? ¿Parece el uso más sencillo de usar y eliminar un puntero? El error dice que la memoria no se asignó pero 'cout' devolvió una dirección.
- En el segundo ejemplo, el error no se activa, pero al hacer un cout del valor de myPointer todavía se devuelve una dirección de memoria.
- ¿El # 3 realmente funciona? Me parece que funciona, el puntero ya no almacena una dirección, ¿es esta la forma correcta de eliminar un puntero?
Perdón por la pregunta larga, quería dejar esto lo más claro posible, también para reiterar, tengo poca experiencia en programación, así que si alguien pudiera responder esto usando términos sencillos, ¡sería muy apreciado!
fuente
delete
lo que tunew
. Tampoco es necesario que el puntero se establezca en NULL después de eliminarlo. Si desea seguridad allí, use punteros inteligentes, que liberan la memoria para usted y dan errores cuando intenta acceder a ellos cuando no contienen algo.reset
y libera al viejo. Para liberarlo sin recambio, llamarelease
. Cuando sale del alcance, se destruye y podría liberar la memoria según el tipo que sea.std::unique_ptr
está destinado a un solo propietario.std::shared_ptr
lo libera cuando el último propietario deja de poseer el recurso. También son excepcionales a salvo. Si asigna un recurso con uno y luego encuentra una excepción, el recurso se liberará correctamente.Respuestas:
1 y 2
myVar = 8; //not dynamically allocated. Can't call delete on it. myPointer = new int; //dynamically allocated, can call delete on it.
La primera variable se asignó a la pila. Puede llamar a eliminar solo en la memoria que asignó dinámicamente (en el montón) usando el
new
operador.3.
myPointer = NULL; delete myPointer;
Lo anterior no hizo nada en absoluto . No liberaste nada, ya que el puntero apuntaba a NULL.
No se debe hacer lo siguiente:
myPointer = new int; myPointer = NULL; //leaked memory, no pointer to above int delete myPointer; //no point at all
Lo apuntó a NULL, dejando atrás la memoria filtrada (el nuevo int que asignó). Deberías liberar la memoria que estabas apuntando. Ya no hay forma de acceder a lo asignado
new int
, por lo tanto, pérdida de memoria.La forma correcta:
myPointer = new int; delete myPointer; //freed memory myPointer = NULL; //pointed dangling ptr to NULL
La mejor forma:
Si está utilizando C ++, no utilice punteros sin formato. En su lugar, use punteros inteligentes que puedan manejar estas cosas por usted con poca sobrecarga. C ++ 11 viene con varios .
fuente
delete myPointer
desasigna*myPointer
. Eso es correcto. PeromyPointer
continúa apuntando a una ubicación de memoria que se ha liberado y no debe usarse ya que es UB. Será inaccesible después del final del alcance solo si fue una variable local en primer lugar.new
todos los días. (¡Soy cursi!)NULL
evita que hagamos un mal uso de él más adelante.Creo que no comprende completamente cómo funcionan los punteros.
Cuando tienes un puntero apuntando a una memoria, hay tres cosas diferentes que debes entender:
- hay "lo que apunta" el puntero (la memoria)
- esta dirección de memoria
- no todos los punteros necesitan borrar su memoria: solo necesita eliminar la memoria que se asignó dinámicamente (
new
operador usado ).Imagina:
int *ptr = new int; // ptr has the address of the memory. // at this point, the actual memory doesn't have anything. *ptr = 8; // you're assigning the integer 8 into that memory. delete ptr; // you are only deleting the memory. // at this point the pointer still has the same memory address (as you could // notice from your 2nd test) but what inside that memory is gone!
Cuando lo hiciste
ptr = NULL; // you didn't delete the memory // you're only saying that this pointer is now pointing to "nowhere". // the memory that was pointed by this pointer is now lost.
C ++ permite que intentes con
delete
un puntero que apunta,null
pero en realidad no hace nada, simplemente no da ningún error.fuente
Los punteros son similares a las variables normales en que no es necesario eliminarlos. Se eliminan de la memoria al final de la ejecución de una función y / o al final del programa.
Sin embargo, puede usar punteros para asignar un 'bloque' de memoria, por ejemplo, como este:
int *some_integers = new int[20000]
Esto asignará espacio de memoria para 20000 enteros. Útil, porque la pila tiene un tamaño limitado y es posible que desee meterse con una gran cantidad de 'ints' sin un error de desbordamiento de pila.
Siempre que llame a new, debe 'eliminar' al final de su programa, porque de lo contrario obtendrá una pérdida de memoria y parte del espacio de memoria asignado nunca será devuelto para que lo usen otros programas. Para hacer esto:
delete [] some_integers;
Espero que ayude.
fuente
nuevo nunca se llama. Entonces, la dirección que imprime cout es la dirección de la ubicación de memoria de myVar, o el valor asignado a myPointer en este caso. Por escrito:
tu dices:
Devuelve una dirección que apunta a una ubicación de la memoria que se ha eliminado. Porque primero creas el puntero y asignas su valor a myPointer, segundo lo eliminas, tercero lo imprimes. Entonces, a menos que asigne otro valor a myPointer, la dirección eliminada permanecerá.
NULL es igual a 0, elimina 0, por lo que no elimina nada. Y es lógico que imprima 0 porque lo hiciste:
myPointer = NULL;
que es igual a:
myPointer = 0;
fuente
fuente
int value, *ptr; value = 8; ptr = &value; // ptr points to value, which lives on a stack frame. // you are not responsible for managing its lifetime. ptr = new int; delete ptr; // yes this is the normal way to manage the lifetime of // dynamically allocated memory, you new'ed it, you delete it. ptr = nullptr; delete ptr; // this is illogical, essentially you are saying delete nothing.
fuente