new diferencia delete c++ memory-management heap-memory

c++ - diferencia - ¿Por qué incluso necesitamos el operador "delete[]"?



heap memory sap (7)

Agregando esto ya que ninguna otra respuesta lo aborda actualmente:

Array delete[] no se puede usar en una clase de puntero a base nunca - mientras el compilador almacena el recuento de objetos cuando se invoca a new[] , no almacena los tipos o tamaños de los objetos (como David señaló , en C ++ rara vez paga por una característica que no está usando). Sin embargo, la delete escalar puede delete manera segura a través de la clase base, por lo que se usa tanto para la limpieza normal de objetos como para la limpieza polimórfica:

struct Base { virtual ~Base(); }; struct Derived : Base { }; int main(){ Base* b = new Derived; delete b; // this is good Base* b = new Derived[2]; delete[] b; // bad! undefined behavior }

Sin embargo, en el caso contrario, el destructor no virtual, la delete escalar debería ser lo más barata posible, no debería verificar el número de objetos ni el tipo de objeto que se elimina. Esto hace que eliminar en un tipo incorporado o en un tipo de datos antiguo sea muy barato, ya que el compilador solo necesita invocar ::operator delete y nada más:

int main(){ int * p = new int; delete p; // cheap operation, no dynamic dispatch, no conditional branching }

Si bien no es un tratamiento exhaustivo de la asignación de memoria, espero que esto ayude a aclarar la amplitud de las opciones de administración de memoria disponibles en C ++.

Esta es una pregunta que me ha estado molestando por un tiempo. Siempre pensé que C ++ debería haber sido diseñado para que el operador "eliminar" (sin paréntesis) funcione incluso con el operador "nuevo []".

En mi opinión, escribiendo esto:

int* p = new int;

debería ser equivalente a asignar una matriz de 1 elemento:

int* p = new int[1];

Si esto fuera cierto, el operador "eliminar" siempre podría estar eliminando matrices, y no necesitaríamos el operador "delete []".

¿Hay alguna razón por la cual el operador "delete []" se introdujo en C ++? La única razón por la que puedo pensar es que la asignación de matrices tiene una pequeña huella de memoria (hay que almacenar el tamaño de la matriz en algún lugar), por lo que distinguir "eliminar" frente a "eliminar []" fue una pequeña optimización de la memoria.


Como todos los demás parecen haber perdido el sentido de su pregunta, agregaré que tuve el mismo pensamiento hace algunos años, y nunca he podido obtener una respuesta.

Lo único que se me ocurre es que hay una muy pequeña sobrecarga adicional para tratar un solo objeto como una matriz (un " for(int i=0; i<1; ++i) innecesario")


Es así que se invocarán los destructores de los elementos individuales. Sí, para arreglos de POD, no hay mucha diferencia, pero en C ++, puede tener matrices de objetos con destructores no triviales.

Ahora, su pregunta es, ¿por qué no hacer new y delete comportarse como new[] y delete[] y deshacerse de new[] y delete[] ? Volvería al libro "Diseño y evolución" de Stroustrup, donde dijo que si no usa las funciones de C ++, no debería tener que pagarlas (en tiempo de ejecución al menos). Tal como está ahora, una new o delete se comportará tan eficientemente como malloc y free . Si delete tenía el significado de delete[] , habría una sobrecarga adicional en el tiempo de ejecución (como señaló James Curran).


Estoy un poco confundido por la respuesta de Aaron y francamente admito que no entiendo completamente por qué y dónde se necesita eliminar [].

Hice algunos experimentos con su código de muestra (después de corregir algunos errores tipográficos). Aquí están mis resultados. Typos: ~ Base necesitaba un cuerpo de función Base * b fue declarado dos veces

struct Base { virtual ~Base(){ }>; }; struct Derived : Base { }; int main(){ Base* b = new Derived; delete b; // this is good <strike>Base</strike> b = new Derived[2]; delete[] b; // bad! undefined behavior }

Compilación y ejecución

david@Godel:g++ -o atest atest.cpp david@Godel: ./atest david@Godel: # No error message

Se eliminó el programa modificado con delete []

struct Base { virtual ~Base(){}; }; struct Derived : Base { }; int main(){ Base* b = new Derived; delete b; // this is good b = new Derived[2]; delete b; // bad! undefined behavior }

Compilación y ejecución

david@Godel:g++ -o atest atest.cpp david@Godel: ./atest atest(30746) malloc: *** error for object 0x1099008c8: pointer being freed was n ot allocated *** set a breakpoint in malloc_error_break to debug Abort trap: 6

Por supuesto, no sé si delete [] b está trabajando realmente en el primer ejemplo; Solo sé que no da un mensaje de error del compilador.


Maldita sea, me perdí el punto de la pregunta, pero dejaré mi respuesta original como nota al margen. La razón por la que tenemos delete [] es porque hace mucho tiempo teníamos delete [cnt], incluso hoy si escribes delete [9] o delete [cnt], el compilador simplemente ignora la cosa entre [] pero compila ok. En ese momento, C ++ fue procesado por un front-end y luego alimentado a un compilador de C ordinario. No podían hacer el truco de almacenar el conteo en algún lugar debajo de la cortina, tal vez ni siquiera podían pensar en eso en ese momento. Y para compatibilidad con versiones anteriores, los compiladores probablemente usaron el valor dado entre [] como el recuento de matriz, si no hay tal valor, obtuvieron el recuento del prefijo, por lo que funcionó en ambos sentidos. Más tarde, no escribimos nada entre [] y todo funcionó. Hoy, no creo que sea necesario "eliminar []", pero las implementaciones así lo exigen.

Mi respuesta original (que no entiende) ::

"Eliminar" borra un solo objeto. "delete []" borra una matriz de objetos. Para que delete [] funcione, la implementación mantiene la cantidad de elementos en la matriz. Acabo de verificar esto al depurar el código ASM. En la implementación (VS2005) que probé, el recuento se almacenó como un prefijo para la matriz de objetos.

Si usa "eliminar []" en un solo objeto, la variable de conteo es basura, por lo que el código falla. Si usa "eliminar" para una matriz de objetos, debido a alguna incoherencia, el código falla. ¡Probé estos casos justo ahora!

"eliminar simplemente elimina la memoria asignada para la matriz". declaración en otra respuesta no es correcta. Si el objeto es una clase, delete llamará al DTOR. Simplemente coloque un punto de corte en el código DTOR y elimine el objeto, el punto de interrupción se activará.

Lo que se me ocurrió es que, si el compilador y las bibliotecas suponían que todos los objetos asignados por "nuevo" son matrices de objetos, sería correcto llamar a "eliminar" para objetos individuales o matrices de objetos. Los objetos únicos serían el caso especial de una matriz de objetos con un recuento de 1. Tal vez haya algo que me falta, de todos modos ...



delete [] asegura que se llama al destructor de cada miembro (si corresponde al tipo) mientras que delete simplemente borra la memoria asignada para la matriz.

Aquí hay una buena lectura: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=287

Y no, los tamaños de matriz no se almacenan en ningún lugar en C ++. (Gracias a todos por señalar que esta afirmación es inexacta).