Una aplicación de prueba simple:
cout << new int[0] << endl;
salidas:
0x876c0b8
Entonces parece que funciona. ¿Qué dice la norma sobre esto? ¿Es siempre legal "asignar" un bloque de memoria vacío?
Una aplicación de prueba simple:
cout << new int[0] << endl;
salidas:
0x876c0b8
Entonces parece que funciona. ¿Qué dice la norma sobre esto? ¿Es siempre legal "asignar" un bloque de memoria vacío?
Respuestas:
Desde 5.3.4 / 7
Cuando el valor de la expresión en un declarador directo nuevo es cero, se llama a la función de asignación para asignar una matriz sin elementos.
Desde 3.7.3.1/2
El efecto de desreferenciar un puntero devuelto como una solicitud de tamaño cero no está definido.
también
Incluso si el tamaño del espacio solicitado [por nuevo] es cero, la solicitud puede fallar.
Eso significa que puede hacerlo, pero no puede desreferenciar legalmente (de una manera bien definida en todas las plataformas) la memoria que obtiene, solo puede pasarla a la eliminación de matriz, y debe eliminarla.
Aquí hay una nota interesante (es decir, no es una parte normativa de la norma, pero se incluye con fines expositivos) adjunta a la oración de 3.7.3.1/2
[32. La intención es que el operador new () sea implementable llamando a malloc () o calloc (), por lo que las reglas son sustancialmente las mismas. C ++ difiere de C al requerir una solicitud cero para devolver un puntero no nulo.]
new[]
con un delete[]
- cualquiera sea el tamaño. En particular, cuando llama new[i]
, necesita un poco más de memoria que la que está tratando de asignar para almacenar el tamaño de la matriz (que luego se utiliza delete[]
cuando se desasigna)
Sí, es legal asignar una matriz de tamaño cero como esta. Pero también debes eliminarlo.
int ar[0];
es ilegal, ¿por qué está bien nuevo?
sizeof (type)
se espera que nunca devuelva cero. Ver por ejemplo: stackoverflow.com/questions/2632021/can-sizeof-return-0-zero
¿Qué dice la norma sobre esto? ¿Es siempre legal "asignar" un bloque de memoria vacío?
Cada objeto tiene una identidad única, es decir, una dirección única, lo que implica una longitud distinta de cero (la cantidad real de memoria aumentará silenciosamente, si solicita cero bytes).
Si asignó más de uno de estos objetos, encontrará que tienen direcciones diferentes.
operator []
también almacena el tamaño de la matriz en algún lugar (ver isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array ). Entonces, si la implementación asigna el recuento de bytes con los datos, simplemente podría asignar el recuento de bytes y 0 bytes para los datos, devolviendo el último puntero.
operator new[]
deberían devolver diferentes punteros. Por cierto, el new expression
tiene algunas reglas adicionales (5.3.4). No pude encontrar ninguna pista de que new
con el tamaño 0 se requiera para asignar algo. Lo siento, rechacé porque encuentro que su respuesta no responde las preguntas, sino que proporciona algunas declaraciones controvertidas.
new[]
implementación devuelva direcciones en un rango donde no hay memoria dinámica asignada, por lo tanto, realmente no usa ninguna memoria (mientras usa el espacio de direcciones)
while(!exitRequested) { char *p = new char[0]; delete [] p; }
bucle sin reciclar punteros colapsaría en polvo antes de que posiblemente se quedara sin espacio de direcciones, pero en una plataforma con punteros de 32 bits sería Suposición mucho menos razonable.
Sí, es completamente legal asignar un 0
bloque de tamaño new
. Simplemente no puede hacer nada útil con él ya que no hay datos válidos para acceder. int[0] = 5;
es ilegal.
Sin embargo, creo que el estándar permite cosas como malloc(0)
regresar NULL
.
También necesitará delete []
cualquier puntero que obtenga de la asignación también.
Curiosamente, C ++ requiere que el operador nuevo devuelva un puntero legítimo incluso cuando se solicitan cero bytes. (Requerir este comportamiento de sonido extraño simplifica las cosas en otras partes del lenguaje).
Encontré que Efective C ++ Third Edition decía así en "Elemento 51: Adherirse a la convención al escribir nuevo y eliminar".
Le garantizo que el nuevo int [0] le cuesta espacio extra desde que lo probé.
Por ejemplo, el uso de memoria de
int **arr = new int*[1000000000];
es significativamente más pequeño que
int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
arr[i]=new int[0];
}
El uso de memoria del segundo fragmento de código menos el del primer fragmento de código es la memoria utilizada para los numerosos nuevos int [0].