eliminar vs eliminar [] operadores en C ++

135

¿Cuál es la diferencia entre deletey delete[]operadores en C ++?

shreyasva
fuente
Puede encontrar esta pregunta relevante stackoverflow.com/questions/1913343/…
sharptooth
77
Los problemas con eliminar y eliminar [] son ​​una de las razones por las que me gustan los punteros inteligentes, y usar en vector<>lugar de una matriz siempre que puedo.
David Thornley
@DavidThornley Si está utilizando punteros inteligentes, aún necesita saber la diferencia en el sentido de que todavía necesita saber que no debe escribir std::unique_ptr<int>(new int[3]), por ejemplo , porque llamará regularmente deleteen la matriz, que es un comportamiento indefinido. En cambio, debe usarstd::unique_ptr<int[]>
Arthur Tacca

Respuestas:

151

El deleteoperador desasigna memoria y llama al destructor para un solo objeto creado con new.

El delete []operador desasigna la memoria y llama a los destructores para una matriz de objetos creados con new [].

El uso deleteen un puntero devuelto por new []o delete []en un puntero devuelto por newresultados en un comportamiento indefinido.

Nick Meyer
fuente
3
Me pregunto si usar delete en una nueva matriz [] de tipos primitivos como int o char (sin constructor / destructor) necesariamente conduce a un comportamiento indefinido también. Parece que el tamaño de la matriz no se almacena en ningún lugar cuando se usan tipos primitivos.
thomiel
21
Si el estándar no define lo que sucede cuando se hace eso, es por definición "comportamiento indefinido", incluso si su compilador determina de manera determinista lo que le gustaría que hiciera. Otro compilador puede hacer algo completamente diferente.
Rob K
Cometí este error cuando tenía una serie de cadenas C como "char ** strArray". Si tiene una matriz como la que tengo, necesita iterar a través de la matriz y eliminar / liberar cada elemento, luego eliminar / liberar el propio strArray. El uso de "eliminar []" en la matriz que tengo no funciona desde entonces (como se señala en los comentarios y respuestas anteriores), LLAMA A DESTRUCTORES, en realidad no libera cada ranura.
Katianie
88

El delete[]operador se utiliza para eliminar matrices. El deleteoperador se utiliza para eliminar objetos que no son de matriz. Llama operator delete[]y operator deletefunciona respectivamente para eliminar la memoria que ocupó la matriz o el objeto no matriz después (eventualmente) de llamar a los destructores para los elementos de la matriz o el objeto no matriz.

A continuación se muestran las relaciones:

typedef int array_type[1];

// create and destroy a int[1]
array_type *a = new array_type;
delete [] a;

// create and destroy an int
int *b = new int;
delete b;

// create and destroy an int[1]
int *c = new int[1];
delete[] c;

// create and destroy an int[1][2]
int (*d)[2] = new int[1][2];
delete [] d;

Para el newque crea una matriz (por lo tanto, new type[]o se newaplica a una construcción de tipo de matriz), el Estándar busca una operator new[]clase de tipo de elemento de la matriz o en el ámbito global, y pasa la cantidad de memoria solicitada. Puede solicitar más de N * sizeof(ElementType)lo que quiere (por ejemplo, almacenar el número de elementos, por lo que más tarde, al eliminar, sabe cuántas llamadas de destructor se realizarán). Si la clase declara operator new[]que un adicional a la cantidad de memoria acepta otro size_t, ese segundo parámetro recibirá el número de elementos asignados; puede usar esto para cualquier propósito que desee (depuración, etc.).

Para el newque crea un objeto sin matriz, buscará un operator newen la clase del elemento o en el ámbito global. Pasa la cantidad de memoria solicitada (exactamente sizeof(T)siempre).

Para delete[]ello, analiza el tipo de clase de elemento de las matrices y llama a sus destructores. La operator delete[]función utilizada es la de la clase del tipo de elemento, o si no hay ninguna en el ámbito global.

Para el delete, si el puntero pasado es una clase base del tipo del objeto real, la clase base debe tener un destructor virtual (de lo contrario, el comportamiento no está definido). Si no es una clase base, se llama al destructor de esa clase y se usa un operator deleteen esa clase o el global operator delete. Si se pasó una clase base, se llama al destructor del tipo de objeto real, y operator deletese utiliza el encontrado en esa clase, o si no hay ninguno, operator deletese llama a un global . Si operator deleteen la clase tiene un segundo parámetro de tipo size_t, recibirá el número de elementos para desasignar.

Johannes Schaub - litb
fuente
18

Este es el uso básico del patrón de asignación / DE-asignación en c ++ malloc/ free, new/ delete, new[]/delete[]

Necesitamos usarlos correspondientemente. Pero me gustaría agregar esta comprensión particular de la diferencia entre deleteydelete[]

1) deletese utiliza para desasignar memoria asignada para un solo objeto

2) delete[]se utiliza para desasignar la memoria asignada para una matriz de objetos

class ABC{}

ABC *ptr = new ABC[100]

cuando decimos new ABC[100], el compilador puede obtener la información sobre cuántos objetos hay que asignar (aquí son 100) y llamará al constructor para cada uno de los objetos creados

pero correspondientemente si simplemente usamos delete ptrpara este caso, el compilador no sabrá a cuántos objetos ptrapunta y terminará llamando al destructor y eliminando memoria para solo 1 objeto (dejando la invocación de los destructores y la desasignación de los 99 objetos restantes). Por lo tanto, habrá una pérdida de memoria.

entonces necesitamos usar delete [] ptren este caso.

ravs2627
fuente
3
Esta debería ser la respuesta correcta. Ninguna de las otras respuestas menciona la diferencia distintiva: "pero en consecuencia si simplemente usamos delete ptr para este caso, el compilador no sabrá a cuántos objetos apunta ptr y terminará llamando al destructor y eliminando memoria para solo 1 objeto"
Don Larynx
1
¿Cómo logramos lo mismo en C?
Dogus Ural
@DogusUral ¿Por qué? No hay destructores en C, así que solo free()esto y aquello. Si usa un patrón de pseudodestructor, debe llamarlo una vez por cada objeto que use un forbucle.
Kotauskas
@DonLarynx la diferencia correcta es que mezclarlos da como resultado un programa mal formado. Una implementación puede saber cuántos objetos destruir, o puede que no . Se permite saber que se llamó incorrectamente y abortar el programa que le dice dónde está el problema.
Caleth
6

Los operadores deletey delete []se utilizan respectivamente para destruir los objetos creados con newy new[], volviendo a la memoria asignada que queda disponible para el administrador de memoria del compilador.

Los objetos creados con newnecesariamente deben destruirse con delete, y las matrices creadas con new[]deben eliminarse con delete[].

san983
fuente
2

Cuando hice esta pregunta, mi pregunta real fue: "¿hay alguna diferencia entre los dos? ¿No tiene que mantener el tiempo de ejecución información sobre el tamaño de la matriz, por lo que no será capaz de decir a qué nos referimos?" Esta pregunta no aparece en "preguntas relacionadas", así que solo para ayudar a aquellos como yo, aquí está la respuesta a eso: "¿por qué necesitamos el operador eliminar []?"

Ekalavya
fuente
Gracias por regresar y poner esto.
Ziffusion
0

deletese usa para un solo puntero y delete[]se usa para eliminar una matriz a través de un puntero. Esto podría ayudarlo a comprender mejor.

nishant arora
fuente
-6

Bueno ... tal vez creo que es solo para explícito. El operador deletey el operador delete[]se distinguen, pero el deleteoperador también puede liberar la matriz.

test* a = new test[100];
delete a;

Y ya comprobado que este código no tiene fuga de memoria.

Hola Mundo
fuente