Llamar a delete en la variable asignada en la pila
-
22-07-2019 - |
Pregunta
Ignorando el estilo y el diseño de la programación, ¿es seguro? llamar a eliminar en una variable asignada en la pila?
Por ejemplo:
int nAmount;
delete &nAmount;
o
class sample
{
public:
sample();
~sample() { delete &nAmount;}
int nAmount;
}
Solución
No , no lo es es seguro llamar a delete
en una variable asignada por pila. Solo debe llamar a delete
en elementos creados por new
.
- Para cada
malloc
ocalloc
, debe haber exactamente unlibre
. - Para cada
new
debe haber exactamente unadelete
. - Para cada
new []
debe haber exactamente undelete []
. - Para cada asignación de pila, no debe haber una liberación o eliminación explícita. El destructor se llama automáticamente, cuando corresponda.
En general, no puede mezclar y combinar ninguno de estos, p. no free
-ing o delete []
-ing un objeto new
. Hacerlo da como resultado un comportamiento indefinido.
Otros consejos
Bueno, probémoslo:
jeremy@jeremy-desktop:~$ echo 'main() { int a; delete &a; }' > test.cpp
jeremy@jeremy-desktop:~$ g++ -o test test.cpp
jeremy@jeremy-desktop:~$ ./test
Segmentation fault
Entonces aparentemente no es seguro en absoluto.
Tenga en cuenta que cuando asigna un bloque de memoria usando new (o malloc para el caso), el bloque de memoria real asignado será mayor que lo que solicitó. El bloque de memoria también contendrá información de contabilidad para que, cuando libere el bloque, pueda volver a colocarse fácilmente en el grupo libre y posiblemente fusionarse con bloques libres adyacentes.
Cuando intentas liberar cualquier memoria que no recibiste de la nueva, esa información de contabilidad no estará allí, pero el sistema actuará como está y los resultados serán impredecibles (generalmente malos).
Sí, es un comportamiento indefinido: pasar a eliminar
cualquier cosa que no provenga de new
es UB:
Estándar C ++, sección 3.7.3.2.3: El valor del primer argumento suministrado a una de las funciones de desasignación proporcionadas en la biblioteca estándar puede ser un valor de puntero
null
; si es así, y si la función de desasignación se proporciona en la biblioteca estándar, la llamada a la función de desasignación no tiene ningún efecto. De lo contrario, el valor proporcionado aoperator delete (void *)
en la biblioteca estándar será uno de los valores devueltos por una invocación previa de cualquiera deoperator new (std :: size_t)
ooperador nuevo (std :: size_t, const std :: nothrow_t & amp;)
en la biblioteca estándar.
Las consecuencias del comportamiento indefinido son, bueno, indefinidas. "No pasa nada" es una consecuencia tan válida como cualquier otra cosa. Sin embargo, por lo general, "nada sucede de inmediato": desasignar un bloqueo de memoria no válido puede tener graves consecuencias en las llamadas posteriores al asignador.
Después de jugar un poco con g ++ 4.4 en Windows, obtuve resultados muy interesantes:
-
llamar a delete en una variable de pila no parece hacer nada. No arrojo errores, pero puedo acceder a la variable sin problemas después de la eliminación.
-
Tener una clase con un método con
delete this
elimina con éxito el objeto si está asignado en el montón, pero no si está asignado en la pila (si está en la pila , no pasa nada).
Nadie puede saber qué pasa. Esto invoca un comportamiento indefinido, por lo que, literalmente, cualquier cosa puede suceder. No hagas esto.
No, La memoria asignada usando new debe eliminarse usando el operador delete y eso asignado usando malloc debería eliminarse usando free. Y no es necesario desasignar la variable que se asigna en la pila.
Un ángel pierde sus alas ... Solo puede llamar a delete
en un puntero asignado con new
, de lo contrario obtendrá un comportamiento indefinido.
aquí la memoria se asigna utilizando la pila, por lo que no es necesario eliminarla de forma manual, pero si se ha citado dinámicamente
me gusta int * a = new int ()
entonces debe eliminar y no eliminar & amp; a (a en sí mismo es un puntero), porque la memoria se asigna desde la tienda libre.
Ya respondiste la pregunta tú mismo. delete
solo debe usarse para punteros obtenidos a través de new
. Hacer cualquier otra cosa es un comportamiento indefinido simple y llano.
Por lo tanto, realmente no hay forma de decir qué sucede, cualquier cosa, desde que el código funcione bien hasta que se bloquee hasta borrar el disco duro, es un resultado válido de hacerlo. Entonces, por favor, nunca hagas esto .
Es UB porque no debe llamar a eliminar en un elemento que no se ha asignado dinámicamente con nuevo. Es así de simple.