2013-07-02 2 views
14

La mia domanda si trovano nel mio commento Codice:allocazione memoria e dimensione 0: posso ottenere perdite di memoria?

int* a = new int[0];// I've expected the nullptr according to my logic... 
bool is_nullptr = !a; // I got 'false' 
delete[] a; // Will I get the memory leaks, if I comment this row? 

Grazie.

+0

Perché dovresti mai allocare byte '0'? – Kolyunya

+3

@Kolyunya Normalmente nessuno lo farebbe, ma cosa succede se la dimensione è una variabile che può essere zero? –

+0

@JoachimPileborg, potresti per favore chiarire il tuo punto? Non riesco ancora a capirlo. La domanda è abbastanza interessante per me. Se chiamiamo 'malloc (0)' chiameremo 'free' dopo? È allocata alcuna memoria? – Kolyunya

risposta

16

per C++ 11, e dato il tuo codice:

int* a = new int[0]; 

Zero è una dimensione legale, come da 5.3.4/7:

Quando il valore dell'espressione in un noptr-new-dichiarator è zero, la funzione di allocazione è chiamata a allocare un array senza elementi.

L'operatore invocata è secondo 18.6.1.2 (sottolineatura mia):

void * operator new [] (std :: size_t size);

...

3 comportamento richiesto: Stesso come per l'operatore new (std :: size_t). Questo requisito è vincolante per la versione sostitutiva di questa funzione.

4 Comportamento predefinito: restituisce operatore nuovo (dimensione).

... riferimento 18.6.1.1 ...

void* operator new(std::size_t size); 

3 comportamento richiesto: Restituire un puntatore non nullo allo stoccaggio (3.7.4), oppure tiro opportunamente allineati a bad_- alloc eccezione. Questo requisito è vincolante per una versione sostitutiva di questa funzione.

Quindi, il puntatore restituito deve essere non nullo.

In seguito è necessario delete[].

+0

Bjarne Stroustrup mi ha risposto: l'operatore new restituisce sempre un puntatore a un oggetto (getta male_alloc in caso di esaurimento della memoria). Se non si usa delete per un nuovo, si ottiene una perdita. L'esatta quantità di memoria trapelata è specifica per l'implementazione, probabilmente due o tre parole. –

+4

@Bush: beh, onestamente mi sento un po 'triste che ti sia preso del tempo con qualcosa che ti era già stato detto, ma ce l'hai ... –

+1

No, ho ricevuto la risposta da B. Stroustrup dopo che la tua risposta è stata contrassegnata come "risposta". –

4

Sì, senza delete ci sarà una perdita di memoria.

Ogni new deve essere associato a delete. Anche se la dimensione allocata dal programmatore è 0. Allocator può allocare più memoria di quella richiesta a causa dei requisiti di allineamento, del sovraccarico di gestione o di qualsiasi altra cosa.

+0

Come sarà una perdita di memoria? Quanta memoria colerà? – Kolyunya

+3

@Kolyunya Immagino che sia fino all'allocatore di memoria. –

+0

Inoltre, l'allocatore deve restituire un nuovo puntatore per ogni 'new int [0]' richiesta e questi puntatori devono essere univoci in tutte le allocazioni. È evidente che dopo un certo numero di 'new' non seguito da' delete', si esauriranno i puntatori – user4815162342

4

In questo caso è implementazione definito se verrà restituito un nullptr o no, ma si deve fare attenzione che non si dereference questo puntatore anche non chiamare delete si tradurrà in una perdita di memoria.

W.r.t a chiamare delete la regola è semplice:
"Se si chiama new è necessario chiamare delete."

Correzione:
Come le citazioni in altre risposte hanno fatto chiaro, non si può tornare un nullptr.

+0

Cosa succederà se non si chiama 'delete' nell'esempio? Quanta memoria colerà? – Kolyunya

+1

@ Kolyunya: Se non si chiama 'cancella', qualunque sia la memoria allocata (* dipende dall'implementazione *) verrà fatta trapelare. L'unica cosa certa è che sarà diverso da zero. –

+0

Ero solito pensare che se si assegnano '0' byte non c'è nulla da eliminare ... Grazie per avere informazioni. – Kolyunya

7

Sì, c'è una perdita e non dipende dall'implementazione.

Questa nuova espressione non può fornire un puntatore nullo. Alloca la memoria chiamando operator new[], che è necessario per "restituire un puntatore non nullo a una memoria adeguatamente allineata, oppure lanciare un'eccezione bad_alloc" (vedere C++ 11 §18.6.1.1/3 e §18.6.1.2/3) .

Inoltre, i requisiti della funzione di allocazione (§3.7.4.1) richiedono che ogni chiamata a una funzione di allocazione restituisca un puntatore distinto da tutti gli altri puntatori che sono stati allocati ma non ancora deallocati. Pertanto, l'implementazione non può semplicemente avere un singolo puntatore "allocazione vuota" che restituisce sempre.

Questo, ogni nuova espressione di matrice alloca qualcosa, anche se l'estensione è zero. Se non lo deallocate tramite delete[], lo hai fatto trapelare.

10

In C++ 03 new int[0] genera un comportamento non definito poiché il valore compreso tra [] deve essere un valore strettamente positivo - lo zero non è valido (5.3.4/6 "Nuovo"). Quindi chiedere se c'è una perdita di memoria in seguito è in un senso inutile.

In C++ 11 new int[0] provoca una chiamata all'allocatore per allocare una matrice di lunghezza zero (5.3.4/7 "Nuovo"). Se la richiesta di allocazione ha esito positivo, viene restituito un puntatore: non c'è nulla nello standard che indichi la quantità di memoria a cui il puntatore del puntatore contiene, a parte che deve essere almeno la dimensione richiesta. Tuttavia, ha almeno l'effetto di allocare almeno un carattere, poiché quell'indirizzo non può essere restituito dall'allocatore fino a quando non è stato liberato. In pratica, l'overhead contabile sarà più di un personaggio.

+1

Oh; Non sapevo di questa differenza tra C++ 03 e C++ 11; molto interessante. C++ 03 include il linguaggio "il _new-expression_ produce un puntatore all'elemento iniziale ** (se presente) ** dell'array" (enfasi il mio). Durante la lettura di questo in C++ 11, ho assunto che questo testo fosse per gestire il caso in cui il conteggio è zero, ma poiché è presente in C++ 03, forse è anche per gestire il caso in cui un modulo di non lancio restituisce null ? –

+4

Il commento su C++ 03 è completamente errato. In C++ 03 (§5.3.4/6): "L'espressione in un nuovo dichiarante diretto deve essere di tipo integrale o di enumerazione (3.9.1) con un valore non negativo ". 0 è un valore non negativo. (Non ci sono, di fatto, variazioni da qui da C++ 98.) –

+1

"Ogni * espressione costante * ... deve ... valutare un valore strettamente positivo" (enfasi dello Standard) - questo parla di codice come 'new float [n] [5]' (esempio tratto dallo standard), dove '5' (* constant-expression *) dovrebbe essere positivo (e valutato in fase di compilazione), e' n' (* espressione *) dovrebbe essere non negativo (e valutato in fase di esecuzione) – anatolyg