2010-11-11 5 views
9

Sto lavorando a un plug-in per un'applicazione, in cui la memoria deve essere allocata dall'applicazione e tenerne traccia. Quindi, gli handle di memoria dovrebbero essere ottenuti dall'applicazione host sotto forma di buffer e in seguito restituirli all'applicazione. Ora, sto pianificando di utilizzare i vettori STL e mi chiedo quale tipo di allocazione di memoria utilizzi internamente.Il vettore STL usa 'nuovo' e 'cancella' per l'allocazione di memoria di default?

Utilizza le funzioni "nuovo" e "elimina" internamente? In tal caso, posso semplicemente sovraccaricare "nuovo" e "cancella" con le mie funzioni? O dovrei creare il mio allocatore di template che sembra un lavoro difficile per me dal momento che non sono così esperto nella creazione di modelli personalizzati.

Qualsiasi suggerimento/codice di esempio è benvenuto. maniglie di memoria possono essere ottenuti dall'applicazione come questa

void* bufferH = NULL; 

bufferH = MemReg()->New_Mem_Handle(size_of_buffer); 
MemReg()->Dispose_Mem_Handle(bufferH); //Dispose it 
+0

Per creare il tuo allocatore vedere questo classico di Matt Austern: http://www.drdobbs.com/184403759 – sbi

+0

@sbi: non ho letto che ancora, ma ricorda che la semantica degli allocatori è cambiata in modo significativo in C++ 11. Sei sicuro che quel classico sia ancora attuale oggi? (Questa non è una domanda retorica ma reale.) – einpoklum

+1

@einpoklum Questo è un commento di 6 anni. Abbiamo due nuove versioni standard e un'altra all'orizzonte. Ovviamente le cose potrebbero essere cambiate da allora. – sbi

risposta

18

vector utilizza std::allocator per impostazione predefinita, e std::allocator è necessario usare operatore globale nuovo (cioè, ::operator new(size_t)) avere la memoria (20.4.1.1). Tuttavia, non è necessario chiamarlo esattamente una volta per chiamata a allocator::allocate.

Quindi sì, se si sostituisce l'operatore globale nuovo allora vector lo utilizzerà, anche se non necessariamente in un modo che consente realmente all'implementazione di gestire la memoria "in modo efficiente". Eventuali trucchi speciali che si desidera utilizzare potrebbero, in linea di principio, essere resi completamente irrilevanti dallo std::allocator che acquisisce memoria in blocchi da 10 MB e sub-allocazione.

Se si dispone di un'implementazione particolare, è possibile osservare come si comporta vector, che è probabilmente sufficiente se la strategia di allocazione pianificata è intrinsecamente specifica della piattaforma.

+1

Tuttavia, altri contenitori possono beneficiare degli allocatori personalizzati. Per alcune applicazioni, un allocatore di pool può migliorare drasticamente le prestazioni dei contenitori basati su nodi come 'std :: map'. –

+1

L'allocazione di piccoli oggetti è anche uno degli argomenti preferiti di Alexandrescu: http://stackoverflow.com/questions/2707909/how-do-i-use-lokis-small-object-allocator –

+0

Grazie per le risposte. Non avrei dovuto usare la parola "efficiente". Intendevo dire che l'applicazione dovrebbe allocare "tutti" la memoria e tenerne traccia, indipendentemente dalle dimensioni o dall'efficienza. Ma dal tuo commento, sembra che l'overloading sia nuovo e che delete dovrebbe funzionare correttamente. – rwb

6

contenitori STL utilizzano un allocatore sono dato al tempo della costruzione, con un default allocator che utilizza operator new e operator delete.

Se l'impostazione predefinita non funziona, è possibile fornire un allocatore personalizzato conforme ai requisiti del contenitore. Ci sono alcuni esempi del mondo reale citati here.

Misurerei le prestazioni usando prima il valore predefinito e ottimizzerò solo se davvero necessario. L'astrazione di allocatore offre un modo relativamente pulito per ottimizzare qui senza una riprogettazione importante. Il modo in cui si utilizza vector potrebbe avere un impatto sulle prestazioni molto maggiore rispetto all'allocatore sottostante (reserve() in anticipo, evitare l'inserimento e la rimozione al centro dell'intervallo di elementi, gestire in modo efficiente la copia degli elementi degli elementi - gli avvertimenti standard ).

+0

@James, @GMan: Ci sono un paio di aspetti specifici che non sono specificati - in particolare, quando e con quale frequenza 'std :: allocator' usa' :: operator new' per ottenere memoria, e come (o anche se) il parametro 'hint' è usato. –

+0

Grazie per la risposta Steve. Riservo il vettore in anticipo ed evito la rimozione e l'inserimento di elementi di medio raggio. Ma non ero sicuro che l'overloading fosse nuovo e delete avrebbe usato la memoria allocata dall'applicazione host. Mi scuso per aver usato la parola "efficiente". – rwb

+0

Non sono necessarie scuse, scrivendo per il pubblico più ampio così come per voi ... è possibile che sia necessario chiarire la proprietà della memoria per ottenere la migliore risposta specifica. Che cosa pensi di archiviare, da dove viene la sua memoria, come viene rilasciato? Un codice di esempio minimo potrebbe aiutare. –

2

Dall'articolo this, "Il concetto di allocatori è stato originariamente introdotto per fornire un'astrazione per diversi modelli di memoria per gestire il problema di avere tipi di puntatori diversi su determinati sistemi operativi a 16 bit (come vicino, lontano e così via)" ...

'lo standard fornisce un allocatore che utilizza internamente gli operatori globali 'nuovo' e 'eliminare''

l'autore sottolinea anche l'interfaccia alocator non è così spaventoso. Come direbbe Neil Buchanan, "provalo tu stesso!"

3

std::vector utilizza le funzioni unitialized_* per costruire i suoi elementi dalla memoria grezza (utilizzando il posizionamento nuovo).Alloca lo storage utilizzando qualsiasi allocatore con cui è stato creato e, per impostazione predefinita, tale allocatore utilizza direttamente ::operator new(size_t) e ::operator delete(void *p) (ad esempio, non è un tipo specifico operator new).

2

L'attuale std::allocator è stato ottimizzato per una dimensione piuttosto grande di oggetti di dimensioni. Non è il massimo quando si tratta di allocare molti piccoli oggetti, né è il migliore per molti oggetti di grandi dimensioni. Detto questo, non è stato scritto anche per applicazioni multi-thread.

Posso suggerire, prima di tentare di scrivere il proprio, di verificare l'allocatore Hoard se si sta andando al percorso multi-thread. (Oppure puoi anche leggere la pagina Intel TBB ugualmente attraente)