c++ - resueltos - Llamar a eliminar en la variable asignada en la pila
memoria malloc (11)
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;
}
Bueno, probemos:
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.
Después de jugar un poco con g ++ 4.4 en Windows, obtuve resultados muy interesantes:
invocar eliminar en una variable de pila no parece hacer nada. No arrojar 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).
Es UB porque no debe invocar eliminar en un elemento que no se haya asignado dinámicamente con nuevo. Es así de simple.
Nadie puede saber lo que sucede. Esto invoca un comportamiento indefinido, por lo que literalmente puede pasar cualquier cosa. No hagas esto
No, la memoria asignada usando new debe eliminarse usando delete operator y la asignada usando malloc debe eliminarse usando free. Y no es necesario desasignar la variable asignada en la pila.
Sí, es un comportamiento indefinido: pasar para delete
cualquier cosa que no venga de new
es UB:
Estándar de 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
null
punteronull
; si es así, y si la función de desasignación es una proporcionada 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 aloperator delete(void*)
en la biblioteca estándar será uno de los valores devueltos por una invocación previa de cualquieroperator new(std::size_t)
uoperator new(std::size_t, const std::nothrow_t&)
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, "no ocurre nada de inmediato": la desasignación de un bloque de memoria no válido puede tener graves consecuencias en llamadas posteriores al asignador.
Tenga en cuenta que cuando asigna un bloque de memoria utilizando new (o malloc para ese caso), el bloque real de memoria asignado será mayor que el que solicitó. El bloque de memoria también contendrá cierta información de contabilidad para que cuando libere el bloque, pueda volver a colocarse fácilmente en el grupo libre y posiblemente combinarse con bloques libres adyacentes.
Cuando intentas liberar cualquier memoria que no hayas recibido de nuevo, esa información de contabilidad no estará allí, pero el sistema actuará como es y los resultados serán impredecibles (generalmente malos).
Un ángel pierde sus alas ... Solo puedes llamar delete
en un puntero asignado con new
, de lo contrario obtendrás un comportamiento indefinido.
Usted ya respondió la pregunta usted mismo. delete
solo se debe utilizar para punteros obtenidos a través de new
. Hacer cualquier otra cosa es un comportamiento simple e indefinido.
Por lo tanto, no hay nada que diga lo que sucede, cualquier cosa, desde el código que funcione bien hasta el borrado de tu disco duro, es un resultado válido al hacer esto. Así que por favor nunca hagas esto .
aquí la memoria se asigna utilizando la pila, por lo que no es necesario eliminarla de forma manual, pero si se ha asignado dinámicamente
como int * a = new int ()
luego debe eliminar y no eliminar a (a a sí mismo es un puntero), ya que la memoria se asigna desde la tienda gratuita.
No , no es seguro llamar a delete
en una variable asignada por pila. Solo debe llamar delete
en elementos creados por new
.
- Para cada
malloc
ocalloc
, debe haber exactamente unofree
. - Para cada
new
debería haber exactamente unadelete
. - Para cada
new[]
debe haber exactamente unadelete[]
. - Para cada asignación de pila, no debe haber liberación o eliminación explícita. El destructor se llama automáticamente, donde corresponda.
En general, no puede mezclar y combinar ninguno de estos, por ejemplo, no free
o delete[]
-ing un new
objeto. Hacerlo da como resultado un comportamiento indefinido.