2015-07-11 12 views
46

Ho appena letto su std::allocator. A mio parere, è più complicato utilizzarlo invece di utilizzare new e delete.Qual è il vantaggio dell'uso di std :: allocator invece di new in C++?

Con allocator dobbiamo allocare esplicitamente memoria heap, costruirla, distruggerla e infine rilasciare la memoria. Allora, perché è stato creato?

In quali casi può essere utilizzato e quando deve essere utilizzato al posto di nuovo ed eliminare?

+1

In C è stata allocata e deallocata memoria. In C++ usi 'new' e' delete' che sono molto più puliti di quello che fai in C. Se stai usando C++, usa 'new' e' delete'. –

+12

La domanda non riguarda 'malloc' ma' std :: allocator'. –

+4

@EvanCarslake E come sono 'new' e' delete' non allocare/deallocare la memoria? La vera differenza è completamente indipendente: Esecuzione di costruttori/distruttori. – deviantfan

risposta

34

std::allocator è l'allocatore di memoria predefinito per i contenitori di libreria standard ed è possibile sostituire i propri allocatori. Ciò consente di controllare il modo in cui i contenitori standard allocano la memoria. Ma non penso che la tua domanda riguardi specificamente lo std::allocator, ma piuttosto la strategia di allocare memoria, quindi di costruire oggetti in quella memoria, piuttosto che usare new T[N], per esempio.

E il motivo è che new T[N] non consente di controllare quali costruttori vengono chiamati. E ti costringe a costruire tutti i tuoi oggetti allo stesso tempo. Ciò è terribile ai fini di, ad esempio, std::vector in cui si desidera allocare solo occasionalmente.

Con un allocatore di memoria non elaborato, è possibile allocare una determinata quantità di memoria, che determina la capacità. Quindi, mentre l'utente aggiunge elementi al vettore (usando il costruttore di sua scelta), è possibile costruire oggetti in questa memoria.

Quindi quando si esaurisce la memoria, si assegna più, in genere il doppio. Se std::vector utilizzato new T[N], dovrebbe ridistribuire ogni volta che si desidera aggiungere o rimuovere un elemento, che sarebbe terribile per le prestazioni. Si dovrebbe anche essere costretti a utilizzare il costruttore predefinito per tutti gli oggetti, il che pone una restrizione non necessaria sui tipi di oggetti che possono essere trattenuti da std::vector.

+0

Penso 's/allocate/construct' in *" Dove si desidera allocare solo occasionalmente "*. – Nawaz

+0

@Nawaz: Beh, immagino entrambi. Ma ho davvero intenzione di allocare lì. Dopo tutto, è possibile implementare il vettore (molto stupidamente) usando 'new T [size]'.Quindi ogni volta che aggiungi un elemento, verrai riallocato con 'new T [++ size]'. Ed ecco di cosa si trattava (penso): usare 'nuovo T [N]' contro separare l'allocazione dalla costruzione. –

+0

Se leggi *** "E ti costringe a costruire tutti i tuoi oggetti allo stesso tempo ... Questo è terribile ..." ***, seguito da *** "Dove vuoi allocare solo occasionalmente." * **. La seconda frase non va bene con * il ragionamento * della frase precedente. Almeno, questo è ciò che sentivo (e sento ancora). – Nawaz

4

Il motivo per questo membro STL è di dare allo sviluppatore un maggiore controllo sulla memoria. Ciò che intendo con questo è, ad esempio, il nuovo operatore non è in realtà solo una operazione in sé. Alla sua base, esegue una riserva di memoria E quindi riempie quello spazio con l'oggetto.

Anche se non riesco a immaginare un caso specifico del mondo reale, è necessario utilizzare std::allocator e simili quando, forse, la distruzione di un dato oggetto potrebbe influire su altri oggetti in memoria.

Diciamo, per amor di discussione, hai creato un tipo di vettore che ogni elemento è doppio-collegato ad un altro oggetto in memoria e vuoi che, al momento della cancellazione di detto vettore, gli oggetti collegati rimuovano il riferimento ad esso.

5

std::allocator è stato creato per consentire agli sviluppatori un maggiore controllo su come viene allocata la memoria. In molti sistemi embedded, la memoria è vincolata e in tipi diversi. Potrebbe non esserci una quantità enorme. Inoltre, l'allocazione della memoria deve essere ridotta al minimo per evitare problemi di frammentazione.

L'allocatore consente anche l'allocazione da diversi pool di memoria. Ad esempio, allocare blocchi di piccole dimensioni sarebbe più efficiente da un piccolo pool di memoria a blocchi.

+1

In effetti gli allocatori sono stati aggiunti all'STL per incapsulare i dettagli del modello di memoria, ad es. sistemi di memoria segmentati con puntatori "vicini" e "lontani" come i primi chip Intel x86, per non consentire la personalizzazione della modalità di allocazione della memoria. Vedere https://www.sgi.com/tech/stl/drdobbs-interview.html e http://www.stlport.org/resources/StepanovUSA.html –

+0

Anche alcuni sistemi relativamente recenti, come la Playstation 3, rendere necessario l'utilizzo di allocatori personalizzati per mappare le strutture dati in specifiche regioni di memoria. Per non parlare dei casi di voler allocare all'interno, ad esempio, una regione 'mmap()' o un buffer IPC o simili. – fluffy

8

Gli allocatori sono un concetto molto importante nella STL. Ogni contenitore è in grado di assumere un allocatore come argomento. Quindi le allocazioni saranno eseguite usando questo allocatore, e non quello standard.

Questo è utile ad es. per allocare oggetti della stessa dimensione in un pool, per migliorare le prestazioni, o potrebbe essere necessario se c'è un'area speciale di memoria in cui gli oggetti devono vivere.

I passaggi di allocazione e costruzione sono separati perché ad es. per il vettore (std::vector::reserve) è importante essere in grado di allocare memoria per uso futuro, ma non (ancora) creare oggetti al suo interno.

Come example è possibile scrivere un allocatore come classe, contenente una matrice di dimensioni fisse e utilizzare tale array per fornire memoria per alcuni contenitori standard. Quindi puoi avere un'istanza di quella classe nello stack e quindi evitare completamente le allocazioni dell'heap per una parte del tuo programma.

See more examples here in this SO post.

[...] quando dovrebbe essere utilizzato [...]

Quando si hanno esigenze specifiche, e più importante quando si scrive propri contenitori generici.

6

Il tuo istinto è giusto. Nel 90% dei casi, utilizzare new. Tuttavia, avviso in strutture come, ad esempio, la struttura dati map.Uno degli argomenti del modello predefinito è class Alloc = allocator<pair<const Key,T>, che definisce in che modo la classe crea nuove istanze di cose e gestisce le istanze esistenti. In questo modo, potresti teoricamente creare il tuo allocatore personale e quindi utilizzarlo per strutture di dati esistenti. Poiché new e delete sono funzioni e non classi, è necessario disporre di std::allocator per rappresentarli e renderli validi argomenti del modello.

36

A mio parere, è più complicato usarlo invece di usare new e delete.

Sì, ma non è destinato a sostituire new e delete, ha uno scopo diverso.

Con allocatore è necessario allocare esplicitamente memoria heap, costruirla, distruggerla e infine rilasciare la memoria.

Quindi perché è stato creato?

Perché a volte si desidera separare l'allocazione e la costruzione in due passaggi (e allo stesso modo separare distruzione e deallocazione in due passaggi). Se non si desidera farlo, non utilizzare un allocatore, utilizzare invece new.

In quali casi può essere utilizzato e quando deve essere utilizzato al posto di nuovo ed eliminare?

Quando è necessario il comportamento di un allocatore, non il comportamento di new e delete, ovviamente! Il caso tipico è quando si implementa un contenitore.

consideri il codice seguente:

std::vector<X> v; 
v.reserve(4);  // (1) 
v.push_back(X{}); // (2) 
v.push_back(X{}); // (3) 
v.clear();   // (4) 

Qui linea (1) deve allocare memoria sufficiente per quattro oggetti, ma non costruirli ancora.Quindi le righe (2) e (3) devono costruire oggetti nella memoria allocata. Quindi la linea (4) deve distruggere quegli oggetti, ma non rilasciare la memoria. Infine, nel distruttore del vettore, tutta la memoria può essere deallocata.

Quindi il vettore non può utilizzare solo new X() o delete &m_data[1] per creare e distruggere gli oggetti, deve eseguire allocazione/deallocazione separatamente dalla costruzione/distruzione. L'argomento del modello di allocatore di un contenitore definisce la politica da utilizzare per (de) allocare memoria e costruire/distruggere oggetti, consentendo di personalizzare l'utilizzo della memoria del contenitore. La politica predefinita è il tipo std::allocator.

Quindi si utilizza un allocatore quando è richiesto un allocatore (ad esempio quando si utilizza un contenitore) e si utilizza std::allocator quando non si desidera fornire un allocatore personalizzato e si desidera solo quello standard.

Non si utilizza un allocatore in sostituzione di new e delete.

4

new e delete sono il modo diretto per creare un oggetto nella memoria dinamica e inizializzarlo. Gli allocatori sono molto di più, perché offrono un controllo completo sulle fasi sopra menzionate.

Con allocatore dobbiamo allocare esplicitamente memoria heap, costruirlo, distruggerlo, e poi finalmente deallocare la memoria.

Infatti allocatori non dovrebbero essere utilizzati per il codice "normale" dove new e delete sarebbe altrettanto bene. Considera una classe come std::map, spesso implementata come un albero: devi deallocare l'intera foglia ogni volta che un oggetto viene cancellato? Gli allocatori consentono di distruggere quell'oggetto, ma di conservare la memoria in modo da non doverlo richiedere di nuovo.

Inoltre, è possibile specializzare un allocatore per un determinato tipo se si conoscono metodi più ottimizzati per il controllo che non è possibile per new e delete.

Problemi correlati