Foo* set = new Foo[100];
// ...
delete [] set;
No pasas los límites de la matriz a delete[]
. ¿Pero dónde se almacena esa información? ¿Está estandarizado?
Foo* set = new Foo[100];
// ...
delete [] set;
No pasas los límites de la matriz a delete[]
. ¿Pero dónde se almacena esa información? ¿Está estandarizado?
Respuestas:
Cuando asigna memoria en el montón, su asignador realizará un seguimiento de la cantidad de memoria que ha asignado. Esto generalmente se almacena en un segmento "principal" justo antes de la memoria que se le asigna. De esa manera, cuando llega el momento de liberar la memoria, el desasignador sabe exactamente cuánta memoria liberar.
free
sabe cuánta memoria desasignar". Sí, el tamaño del bloque de memoria se almacena "en algún lugar" malloc
(normalmente en el bloque mismo), así que así es como se free
sabe. Sin embargo, new[]
/ delete[]
es una historia diferente. Este último básicamente funciona sobre malloc
/ free
. new[]
también almacena el número de elementos que creó en el bloque de memoria (independientemente de malloc
), para que luego delete[]
pueda recuperar y usar ese número para llamar al número correcto de destructores.
malloc
) y recuento de elementos (por new[]
). Tenga en cuenta que el primero no se puede usar para calcular el segundo, ya que, en general, el tamaño del bloque de memoria puede ser mayor de lo realmente necesario para la matriz del tamaño solicitado. También tenga en cuenta que el contador de elementos de matriz solo es necesario para tipos con destructor no trivial. Para los tipos con destructor trivial, el contador no se almacena new[]
y, por supuesto, no se recupera delete[]
.
UNO DE LOS enfoques para los compiladores es asignar un poco más de memoria y almacenar un recuento de elementos en un elemento principal.
Ejemplo de cómo se podría hacer:
aquí
int* i = new int[4];
el compilador asignará sizeof(int)*5
bytes.
int *temp = malloc(sizeof(int)*5)
Almacenará "4" en los primeros sizeof(int)
bytes
*temp = 4;
y establecer i
i = temp + 1;
Entonces i
señalará una matriz de 4 elementos, no 5.
Y eliminación
delete[] i;
se procesará de la siguiente manera:
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)
La información no está estandarizada. Sin embargo, en las plataformas en las que he trabajado, esta información se almacena en la memoria justo antes del primer elemento. Por lo tanto, teóricamente podrías acceder e inspeccionarlo, sin embargo, no vale la pena.
Además, esta es la razón por la que debe usar eliminar [] cuando asignó memoria con la nueva [], ya que la versión de matriz de eliminar sabe que (y dónde) debe buscar para liberar la cantidad correcta de memoria, y llamar al número apropiado de destructores para los objetos
Básicamente se organiza en memoria como:
[info] [mem que pediste ...]
Donde información es la estructura utilizada por su compilador para almacenar la cantidad de memoria asignada, y qué no.
Sin embargo, esto depende de la implementación.
Está definido en el estándar C ++ para ser específico del compilador. Lo que significa magia de compilación. Se puede romper con restricciones de alineación no triviales en al menos una plataforma principal.
Puede pensar en posibles implementaciones al darse cuenta de que delete[]
solo se define para los punteros devueltos por new[]
, que pueden no ser el mismo puntero devuelto por operator new[]
. Una implementación en la naturaleza es almacenar el recuento de matrices en el primer int devuelto por operator new[]
y new[]
devolver un desplazamiento de puntero más allá de eso. (Es por eso que las alineaciones no triviales pueden romperse new[]
).
Tenga en cuenta que operator new[]/operator delete[]
! = new[]/delete[]
.
Además, esto es ortogonal a cómo C conoce el tamaño de la memoria asignada por malloc
.
Porque la matriz que se 'eliminará' debería haberse creado con un solo uso del operador 'nuevo'. La 'nueva' operación debería haber puesto esa información en el montón. De lo contrario, ¿cómo podrían los usos adicionales de new saber dónde termina el montón?
No está estandarizado. En el tiempo de ejecución de Microsoft, el nuevo operador usa malloc () y el operador de eliminación usa free (). Entonces, en esta configuración, su pregunta es equivalente a lo siguiente: ¿Cómo sabe free () el tamaño del bloque?
Hay algo de contabilidad detrás de escena, es decir, en el tiempo de ejecución C.
Este es un problema más interesante de lo que podrías pensar al principio. Esta respuesta es sobre una posible implementación.
En primer lugar, mientras que en algún nivel su sistema tiene que saber cómo 'liberar' el bloque de memoria, el malloc / free subyacente (que generalmente se llama a new / delete / new [] / delete []) no siempre recuerda exactamente cuánta memoria si lo solicita, se puede redondear (por ejemplo, una vez que está por encima de 4K, a menudo se redondea al siguiente bloque de tamaño 4K).
Por lo tanto, incluso si pudiera obtener el tamaño del bloque de memoria, eso no nos dice cuántos valores hay en la nueva memoria [] ed, ya que puede ser más pequeña. Por lo tanto, tenemos que almacenar un número entero adicional que nos dice cuántos valores hay.
EXCEPTO, si el tipo que se está construyendo no tiene un destructor, entonces eliminar [] no tiene que hacer nada excepto liberar el bloque de memoria, ¡y por lo tanto no tiene que almacenar nada!