Scott Meyers dice nel suo libro Effective C++: Item 5: Utilizzare lo stesso modulo negli usi corrispondenti di new e delete.
La grande domanda per eliminare è questa: quanti oggetti risiedono nella memoria che si sta cancellando? La risposta a ciò determina quanti distruttori devono essere chiamati.
Il puntatore che viene eliminato punta a un singolo oggetto oa una matrice di oggetti? L'unico modo per cancellare sapere è che tu lo dica. Se non si utilizzano parentesi nell'uso di Elimina, Elimina assume che un singolo oggetto sia puntato.
Inoltre, l'allocatore memoria potrebbe allocare più spazio necessario per memorizzare gli oggetti e in questo caso dividendo la dimensione del blocco di memoria restituita dalla dimensione di ciascun oggetto non funzionerà.
A seconda della piattaforma, i _msize
(finestre), malloc_usable_size
(Linux) o malloc_size
funzioni (OSX) vi dirà la vera lunghezza del blocco che è stato assegnato. Queste informazioni possono essere sfruttate nella progettazione di contenitori in crescita.
Un altro motivo per cui non funziona è che Foo* foo = new Foo[10]
chiama operator new[]
per allocare la memoria. Quindi delete [] foo;
chiama operator delete[]
per deallocare la memoria. Poiché tali operatori possono essere sovraccaricati, è necessario attenersi alla convenzione altrimenti operator delete
chiamate che possono avere un'implementazione incompatibile con operator delete []
. È una questione di semantica, non solo di tenere traccia del numero di oggetti allocati per poi rilasciare il giusto numero di chiamate distruttore.
Consulta anche:
[16.14] After p = new Fred[n], how does the compiler know there are n objects to be destructed during delete[] p?
Risposta breve: Magia.
Risposta lunga: il sistema di runtime memorizza il numero di oggetti, n, da qualche parte dove può essere recuperato se si conosce solo il puntatore, p. Ci sono due tecniche popolari che fanno questo. Entrambe queste tecniche sono utilizzate da compilatori di livello commerciale, entrambi hanno dei compromessi, e nessuno dei due è perfetto.Queste tecniche sono:
EDIT: dopo aver commenti @AndreyT leggere, ho scavato nella mia copia di Stroustrup di "The Design e l'evoluzione di C++" e Tratto il seguente:
Come possiamo garantire che un array è stato correttamente cancellato? In particolare, come possiamo garantire che il distruttore venga chiamato per tutti gli elementi di un array?
...
Plain cancellare non è tenuto a gestire sia singoli oggetti un array. Ciò evita di complicare il caso comune di allocazione e deallocazione di singoli oggetti. Evita inoltre di ingombrare oggetti singoli con le informazioni necessarie per la deallocazione dell'array.
Una versione intermedia di delete [] richiedeva al programmatore di specificare il numero di elementi dell'array.
...
Tale rivelata troppo soggetto a errori, così l'onere di mantenere traccia del numero di elementi è stato posto sull'attuazione invece.
Come detto da @Marcus, il razionale potrebbe essere stato "non si paga per quello che non si usa".
EDIT2:
In "The C++ Programming Language, 3 ° edizione", §10.4.7, Bjarne Stroustrup scrive:
Esattamente come gli array e singoli oggetti sono allocati è specifica di esecuzione dipendente. Pertanto, diverse implementazioni reagiranno in modo diverso agli usi non corretti degli operatori delete ed delete []. In casi semplici e non interessanti come il precedente, un compilatore può rilevare il problema, ma in genere qualcosa di brutto si verifica in fase di esecuzione.
L'operatore di distruzione speciale per gli array, delete [], non è logicamente necessario. Tuttavia, supponiamo che l'implementazione dell'archivio gratuito sia stata richiesta per contenere informazioni sufficienti per ogni oggetto per stabilire se si trattava di un individuo o di un array. L'utente avrebbe potuto essere sollevato da un onere, ma quell'obbligo avrebbe imposto significativi overhead di tempo e spazio su alcune implementazioni C++.
+1 per il libro di Scott Meyers: tutti i programmatori C++ dovrebbero possedere e leggere i libri C++ efficaci e più efficaci C++. – AAT
La * spiegazione * di Scott non è affatto una spiegazione. È una mera asserzione del fatto, astutamente spacciata come una "spiegazione". Dice che l'unico modo per sapere se si tratta di un array o di un singolo oggetto è chiedere all'utente. Questo è, naturalmente, errato. È perfettamente possibile memorizzare tali informazioni in 'new []' e quindi recuperare in 'delete', proprio come è ora con il conteggio degli elementi. La decisione è stata presa contro di essa, perché avrebbe eccessivamente complicato la struttura delle informazioni "domestiche" e le ramificazioni in "delete". Non c'è una spiegazione "bella", è stata semplicemente * deciso * in quel modo. – AnT
@Jason: No, la spiegazione di Scott è completamente falsa. Di nuovo, come fai a sapere quanti elementi ci sono nell'array quando fai 'delete []'? Eh? Devi dirgli di 'cancellare [] 'te stesso? No. 'cancella []' "sa" perché utilizza le informazioni sulla famiglia preparate da 'new []'. In exacty allo stesso modo potremmo forzare 'new' \' new [] 'per memorizzare ulteriori informazioni sulla famiglia di" array o non "natura. È facile e ovvio. Questa è la risposta alla tua domanda. – AnT