2012-01-30 25 views
5

se observa El tamaño diferente de la asignación de memoria durante la creación del objeto de la clase C de abajo,de asignación de memoria en C++ creación de objetos

class C { 
int i; 
int j; 
}; 

void f() { 
C *c = new C; 
C *c2 = new C[2]; 
C (*c3)[2] = new C[2][2]; 
} 

c se asigna con 8 bytes;

c2 se asigna con 8 * 2 + 4 bytes;

c3 tiene asignado 8 * 2 * 2 + 4 bytes.

¿Por qué c2 y c3 adquieren 4 bytes más?

+5

Es esta una pregunta tarea? – templatetypedef

+1

es un poco mi propia tarea. :) – sof

+0

¿Cómo se mide la cantidad de memoria asignada? –

Respuesta

8

Recuerde que C++ separa asignación de memoria y objeto de expresión. La nueva matriz predeterminada-T * p = new T[N]; asigna memoria suficiente para los objetos Ny construye esos objetos. En el otro extremo, delete[] p; debe llamar al destructor de todos esos elementos y luego liberar la memoria.

Mientras que la asignación y liberación de la memoria es manejada por la plataforma, y ​​la memoria libre está suficientemente identificada al sistema operativo por un único valor de puntero, la construcción y destrucción de objetos es más complicada. El número de objetos reales debe almacenarse en algún lugar, y para ese fin, el estándar permite que una implementación de C++ solicite más memoria que N * sizeof(T). Es cierto que el puntero p siempre apuntará al comienzo de la matriz de objetos N, pero p no tiene que ser el mismo puntero devuelto por el asignador de memoria subyacente. (De hecho, p se garantiza que es precisamente el valor del resultado de asignación subyacente compensado por la cantidad excesiva de memoria).

Los detalles se dejan completamente a la implementación.Sin embargo, algunas plataformas brindan garantías adicionales; Por ejemplo, el Itanium ABI (que llama a los datos adicionales "matriz cookie") dice que se presentó a la memoria para new T[N] de la siguiente manera:

+- alignof(T) --+-- sizeof(T) --+-- sizeof(T) --+-- sizeof(T) --+-- ... 
| ***** [8B: N] | 1st element | 2nd element | 3rd element | ..... 
+---------------+---------------+---------------+---------------+-- ... 
A    A 
|    |_ result of "new T[N]" 
| 
|_ value returned "operator new[]()" 
+0

Thx para la información detallada. Acabo de descubrir que la plataforma de 32 bits usa estos 32/8 = 4 bytes adicionales para almacenar el tamaño total de los objetos asignados por la expresión 'new []'. – sof

+0

@Kerrek, y ¿qué sucede si tengo una sobrecarga 'operator new [] (size_t n)' - ¿hay alguna garantía de que 'new C [2]' daría 'n' que es exactamente 2 * sizeof (C)? – Andrey

+0

@Andrey: no, no está relacionado. Cualquiera que sea el operador de array nuevo que reciba llamadas recibirá un argumento de tamaño que incluye el requisito de espacio adicional. –

4

Desde el estándar (sección [expr.mew]):

A nueva expresión pasa la cantidad de espacio requerido para la función de asignación como el primer argumento de tipo std::size_t. Ese argumento no será menor que el tamaño del objeto que se está creando; puede ser mayor que el tamaño del objeto que se crea solo si el objeto es una matriz.

Claramente el estándar espera alguna información adicional que se almacena con una matriz asignada dinámicamente.

Ahora, use su depurador para ver lo que está rellenado en esos bytes adicionales, y descubra cuándo puede necesitar esa información adicional para que el compilador haga su trabajo.

(Pista: arreglar su programa para que no se escape de memoria)

3

Una gran cantidad de compiladores utilizan los 4 bytes antes de que el puntero volvió de nuevo [] para almacenar el número de objetos en realidad ser asignados. Esto es todo depende de la implementación y es importante recordar que la aritmética de punteros que le lleva fuera del rango de memoria que asigna los resultados en un comportamiento indefinido