Ottimizzare C++/Scrivere codice C++ efficiente/Allocazioni e deallocazioni: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Nuova pagina: L’allocazione e la deallocazione di memoria dinamica sono operazioni molto lente, se confrontate con l’allocazione e la deallocazione di memoria automatica, cioè su stack. Inoltr...
(Nessuna differenza)

Versione delle 23:25, 21 mag 2008

L’allocazione e la deallocazione di memoria dinamica sono operazioni molto lente, se confrontate con l’allocazione e la deallocazione di memoria automatica, cioè su stack.

Inoltre, tale tipo di allocazione comporta uno spreco di spazio per ogni allocazione, genera frammentazione della memoria virtuale, e produce una scarsa località dei dati, con conseguente scadente utilizzo sia delle cache dei dati della CPU che della memoria virtuale.

Tale allocazione/deallocazione in linguaggio C veniva fatta con le funzioni malloc e free. In C++, pur essendo ancora disponibili tali funzioni, le funzioni normalmente usate a tale scopo sono gli operatori new, new[], delete, e delete[].

Ovviamente, un modo di ridurre le allocazioni è ridurre il numero di oggetti costruiti, e quindi la sezione “Come evitare inutili costruzioni e le distruzioni di oggetti” serve indirettamente anche allo scopo di questa sezione.

Tuttavia, qui si presenteranno regole per ridurre il numero di allocazioni di memoria per un dato numero di chiamate all'operatore new.

Array di lunghezza fissa

Se un array statico o non grande ha lunghezza costante, non usare un oggetto vector, ma usa un array del C, o un oggetto boost:array.

I vector memorizzano i dati in un buffer allocato dinamicamente, mentre le altre soluzioni proposte allocano i dati nell'oggetto stesso. Questo consente di evitare allocazioni/deallocazioni di memoria dinamica e di favorire la località dei dati.

Se l'array è medio o grande, tali vantaggi diminuiscono, e invece risulta più importante evitare di usare troppo spazio sullo stack.

Allocatore a blocchi

Se devi allocare numerosi blocchi di memoria della stessa dimensione, assicurati di usare un allocatore a blocchi.

Un allocatore a blocchi (detto anche allocatore a pool) alloca blocchi di memoria medi o grandi, e fornisce servizi di allocazione/deallocazione di blocchi più piccoli di dimensione costante, offrendo alta velocità di allocazione/deallocazione, bassa frammentazione della memoria, uso efficiente delle cache dei dati e della memoria virtuale.

In particolare, un allocatore di questo tipo migliora notevolmente le prestazioni dei contenitori std::list, std::set, std::multi_set, std::map, e std::multi_map.

Se la tua implementazione della libreria standard non usa già un allocatore a blocchi per questi contenitori, dovresti procurartene uno (per esempio, questo: http://www.codeproject.com/KB/stl/blockallocator.aspx), e specificarlo come parametro di template per le istanze di tali template di contenitori.

Aggiunta di elementi a collezione

Per aggiungere elementi in fondo a una collezione, usa push_back per aggiungere un singolo elemento, back_inserter per far aggiungere elementi a un algoritmo STL, insert per inserire una sequenza.

La funzione push_back garantisce un tempo lineare ammortizzato, in quanto, nel caso del vector, ingrandisce esponenzialmente la capacità.

La classe back_inserter chiama internamente la funzione push_back.

La funzione insert permette di inserire in modo ottimizzato un'intera sequenza, e quindi una chiamata di questo tipo è più veloce di numerose chiamate a push_back.