Domanda

Questa è una domanda che mi assilla da un po 'di tempo. Ho sempre pensato che C ++ avrebbe dovuto essere progettato in modo tale che " elimina " operatore (senza parentesi) funziona anche con il "nuovo []" operatore.

Secondo me, scrivendo questo:

int* p = new int;

dovrebbe essere equivalente all'assegnazione di un array di 1 elemento:

int* p = new int[1];

Se ciò fosse vero, il " elimina " l'operatore potrebbe sempre eliminare le matrici e non avremmo bisogno di " delete [] " operatore.

C'è qualche motivo per cui " delete [] " operatore è stato introdotto in C ++? L'unico motivo a cui riesco a pensare è che l'allocazione di array ha un ingombro di memoria ridotto (è necessario memorizzare la dimensione dell'array da qualche parte), in modo tale da distinguere "elimina". vs " elimina [] " era una piccola ottimizzazione della memoria.

È stato utile?

Soluzione

È così che verranno chiamati i distruttori dei singoli elementi. Sì, per le matrici di POD, non c'è molta differenza, ma in C ++ puoi avere matrici di oggetti con distruttori non banali.

Ora, la tua domanda è: perché non fare in modo che new e delete si comportino come new [] e delete [] e sbarazzarsi di new [] e delete [] ? Ritornerei indietro "Design ed Evolution" di Stroustrup prenota dove ha detto che se non usi le funzionalità C ++, non dovresti pagarle (almeno in fase di esecuzione). Allo stato attuale, un nuovo o elimina si comporterà in modo efficiente come malloc e gratuito . Se delete avesse il significato di delete [] , ci sarebbe un ulteriore sovraccarico in fase di esecuzione (come sottolineato da James Curran).

Altri suggerimenti

Accidenti, ho perso l'intero punto della domanda, ma lascerò la mia risposta originale come sidenote. Perché abbiamo eliminato [] è perché molto tempo fa abbiamo eliminato [cnt], anche oggi se scrivi delete [9] o elimina [cnt], il compilatore ignora la cosa tra [] ma compila ok. A quel tempo, il C ++ veniva prima elaborato da un front-end e quindi inviato a un normale compilatore C. Non potevano fare il trucco di conservare il conteggio da qualche parte sotto il sipario, forse non potevano nemmeno pensarci in quel momento. E per compatibilità con le versioni precedenti, i compilatori probabilmente hanno usato il valore indicato tra [] come conteggio dell'array, se non esiste un valore simile, hanno ottenuto il conteggio dal prefisso, quindi ha funzionato in entrambi i modi. Più tardi, non abbiamo scritto nulla tra [] e tutto ha funzionato. Oggi non penso che " delete [] " è necessario ma le implementazioni lo richiedono in questo modo.

La mia risposta originale (che manca il punto) ::

" eliminare " elimina un singolo oggetto. & Quot; delete [] " elimina un array di oggetti. Per eliminare [] per funzionare, l'implementazione mantiene il numero di elementi nell'array. Ho appena ricontrollato questo eseguendo il debug del codice ASM. Nell'implementazione (VS2005) che ho testato, il conteggio è stato memorizzato come prefisso nell'array di oggetti.

Se usi " elimina [] " su un singolo oggetto, la variabile count è immondizia, quindi il codice si arresta in modo anomalo. Se utilizzi " elimina " per un array di oggetti, a causa di alcune incoerenze, il codice si arresta in modo anomalo. Ho testato questi casi proprio ora!

" delete elimina solo la memoria allocata per l'array. " l'affermazione in un'altra risposta non è giusta. Se l'oggetto è una classe, delete chiamerà il DTOR. Basta inserire un punto di interruzione nel codice DTOR ed eliminare l'oggetto, il punto di interruzione colpirà.

Quello che mi è successo è che, se il compilatore & amp; le biblioteche presumevano che tutti gli oggetti allocati da " new " sono matrici di oggetti, sarebbe OK chiamare " elimina " per singoli oggetti o matrici di oggetti. I singoli oggetti sarebbero il caso speciale di un array di oggetti con un numero di 1. Forse c'è qualcosa che mi manca, comunque ...

Dal momento che tutti gli altri sembrano aver perso il punto della tua domanda, aggiungerò semplicemente che ho avuto lo stesso pensiero qualche anno fa e non sono mai stato in grado di ottenere una risposta.

L'unica cosa che mi viene in mente è che c'è un po 'di sovraccarico extra per trattare un singolo oggetto come un array (un inutile " per (int i = 0; i < 1; ++ i ) ")

Aggiungendo questo dato che nessun'altra risposta al momento lo risolve:

L'array delete [] non può mai essere usato su una classe da puntatore a base - mentre il compilatore memorizza il conteggio degli oggetti quando invochi new [] , non memorizza i tipi o le dimensioni degli oggetti (come ha sottolineato David, in C ++ raramente paghi per una funzionalità che non stai utilizzando). Tuttavia, delete scalare può eliminare in modo sicuro attraverso la classe base, quindi viene utilizzato sia per la normale pulizia degli oggetti che per la pulizia polimorfica:

struct Base { virtual ~Base(); };
struct Derived : Base { };
int main(){
    Base* b = new Derived;
    delete b; // this is good

    Base* b = new Derived[2];
    delete[] b; // bad! undefined behavior
}

Tuttavia, nel caso contrario - distruttore non virtuale - delete scalare dovrebbe essere il più economico possibile - non dovrebbe controllare il numero di oggetti, né il tipo di oggetto cancellato. Ciò rende la cancellazione su un tipo incorporato o un tipo di dati semplicemente vecchio molto economico, poiché il compilatore deve solo invocare :: operator delete e nient'altro:

int main(){
    int * p = new int;
    delete p; // cheap operation, no dynamic dispatch, no conditional branching
}

Pur non trattando in modo esauriente l'allocazione della memoria, spero che ciò aiuti a chiarire l'ampiezza delle opzioni di gestione della memoria disponibili in C ++.

Marshall Cline ha alcune informazioni su questo argomento .

delete [] assicura che venga chiamato il distruttore di ogni membro (se applicabile al tipo) mentre delete elimina semplicemente la memoria allocata per l'array.

Ecco una buona lettura: http: //www.informit. com / guide / content.aspx g = cplusplus & amp;? seqNum = 287

E no, le dimensioni degli array non sono memorizzate in alcun punto in C ++. (Grazie a tutti per aver sottolineato che questa affermazione non è precisa.)

Sono un po 'confuso dalla risposta di Aaron e ammetto francamente di non capire del tutto perché e dove è necessario eliminare [].

Ho fatto alcuni esperimenti con il suo codice di esempio (dopo aver corretto alcuni errori di battitura). Ecco i miei risultati     Typos: ~ Base aveva bisogno di un corpo di funzione     La base * b è stata dichiarata due volte

struct Base { virtual ~Base(){ }>; };
struct Derived : Base { };
int main(){
Base* b = new Derived;
delete b; // this is good

<strike>Base</strike> b = new Derived[2];
delete[] b; // bad! undefined behavior
}

Compilazione ed esecuzione

david@Godel:g++ -o atest atest.cpp 
david@Godel: ./atest 
david@Godel: # No error message

Programma modificato con delete [] rimosso

struct Base { virtual ~Base(){}; };
struct Derived : Base { };

int main(){
    Base* b = new Derived;
    delete b; // this is good

    b = new Derived[2];
    delete b; // bad! undefined behavior
}

Compilazione ed esecuzione

david@Godel:g++ -o atest atest.cpp 
david@Godel: ./atest 
atest(30746) malloc: *** error for object 0x1099008c8: pointer being freed was n
ot allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

Naturalmente, non so se delete [] b stia effettivamente lavorando nel primo esempio; So solo che non fornisce un messaggio di errore del compilatore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top