Una semplice app di prova:
cout << new int[0] << endl;
uscite:
0x876c0b8
Quindi sembra che funzioni. Cosa dice lo standard al riguardo? È sempre legale "allocare" un blocco di memoria vuoto?
Una semplice app di prova:
cout << new int[0] << endl;
uscite:
0x876c0b8
Quindi sembra che funzioni. Cosa dice lo standard al riguardo? È sempre legale "allocare" un blocco di memoria vuoto?
Risposte:
Dal 5.3.4 / 7
Quando il valore dell'espressione in un nuovo dichiaratore diretto è zero, la funzione di allocazione viene chiamata per allocare un array senza elementi.
Dal 3.7.3.1/2
L'effetto del dereferenziamento di un puntatore restituito come richiesta di dimensione zero non è definito.
Anche
Anche se la dimensione dello spazio richiesto [da nuovo] è zero, la richiesta può fallire.
Ciò significa che puoi farlo, ma non puoi legalmente (in modo ben definito su tutte le piattaforme) dereferenziare la memoria che ottieni - puoi solo passarla all'array array - e dovresti eliminarla.
Ecco un'interessante nota (cioè non una parte normativa dello standard, ma inclusa a fini espositivi) allegata alla frase del 3.7.3.1/2
[32. L'intento è di avere un operatore new () implementabile chiamando malloc () o calloc (), quindi le regole sono sostanzialmente le stesse. C ++ differisce da C nel richiedere una richiesta zero per restituire un puntatore non nullo.]
new[]
con a delete[]
- qualunque sia la dimensione. In particolare, quando chiami new[i]
hai bisogno di un po 'più di memoria di quella che stai tentando di allocare per memorizzare le dimensioni dell'array (che verrà successivamente utilizzato delete[]
durante la deallocazione)
Sì, è legale allocare un array di dimensioni zero come questo. Ma devi anche cancellarlo.
int ar[0];
è illegale perché è nuovo OK?
sizeof (type)
dovrebbe mai restituire zero. Si veda ad esempio: stackoverflow.com/questions/2632021/can-sizeof-return-0-zero
Cosa dice lo standard al riguardo? È sempre legale "allocare" un blocco di memoria vuoto?
Ogni oggetto ha un'identità univoca, ovvero un indirizzo univoco, che implica una lunghezza diversa da zero (la quantità effettiva di memoria verrà aumentata in silenzio, se si richiedono zero byte).
Se assegnassi più di uno di questi oggetti, scopriresti che hanno indirizzi diversi.
operator []
memorizza anche la dimensione dell'array da qualche parte (vedi isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array ). Pertanto, se l'implementazione alloca il conteggio dei byte con i dati, potrebbe semplicemente allocare per il conteggio dei byte e 0 byte per i dati, restituendo il puntatore 1-last-last.
operator new[]
dovrebbero restituire puntatori diversi. A proposito, il new expression
ha alcune regole aggiuntive (5.3.4). Non sono riuscito a trovare alcun indizio che new
con la dimensione 0 sia effettivamente necessario per allocare qualcosa. Siamo spiacenti, ho annullato il voto perché trovo che la tua risposta non risponda alle domande, ma fornisca alcune dichiarazioni controverse.
new[]
implementazione restituisca gli indirizzi in un intervallo in cui non è mappata la memoria dinamica, quindi non utilizza realmente alcuna memoria (mentre si utilizza lo spazio degli indirizzi)
while(!exitRequested) { char *p = new char[0]; delete [] p; }
ciclo senza riciclare i puntatori collasserebbe in polvere prima che potesse esaurire lo spazio degli indirizzi, ma su una piattaforma con puntatori a 32 bit che sarebbe un presupposto molto meno ragionevole.
Sì, è completamente legale allocare un 0
blocco di dimensioni con new
. Semplicemente non puoi farci nulla di utile poiché non ci sono dati validi per l'accesso. int[0] = 5;
è illegale.
Tuttavia, credo che lo standard consenta il malloc(0)
ritorno di cose come NULL
.
Avrai comunque bisogno di delete []
qualunque puntatore ti venga restituito dall'allocazione.
Curiosamente, C ++ richiede che l'operatore new restituisca un puntatore legittimo anche quando sono richiesti zero byte. (Richiedere questo comportamento dal suono strano semplifica le cose altrove nella lingua.)
Ho trovato che la terza edizione effettiva di C ++ dicesse così in "Articolo 51: aderire alla convenzione quando si scrive nuovo ed elimina".
Ti garantisco che il nuovo int [0] ti costa più spazio da quando l'ho provato.
Ad esempio, l'utilizzo della memoria di
int **arr = new int*[1000000000];
è significativamente più piccolo di
int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
arr[i]=new int[0];
}
L'utilizzo della memoria del secondo frammento di codice meno quello del primo frammento di codice è la memoria utilizzata per i numerosi nuovi int [0].