2009-07-10 23 views
25

C'è un modo per ridurre la capacità di un vettore?ridurre la capacità di un vettore stl

Il mio codice inserisce valori in un vettore (non conoscendo il loro numero in anticipo) e al termine, i vettori vengono utilizzati solo per le operazioni di lettura.

Immagino di poter creare un nuovo vettore, eseguire un .reseve() con le dimensioni e copiare gli elementi , ma non mi piace l'operazione di copia aggiuntiva.

PS: Non mi interessa una soluzione portatile, a patto che funzioni per gcc.

+4

Solo una nota, riserva() non necessariamente riserva l'importo esatto si passa ad esso; riserva un importo maggiore o uguale all'importo che passi per prenotare(). – DeadHead

+1

Si noti che l'idioma swap esegue una copia. Non so se GCC ha un'estensione per rilasciare la memoria riservata inutilizzata. Secondo me, un tale metodo dovrebbe essere nello standard per il vettore <>. –

+4

Considera l'utilizzo di una deque anziché di un vettore. È quasi veloce quanto il vettore, ma non conserva i dati in blocchi contigui e non ha bisogno di riserva() – Wacek

risposta

37
std::vector<T>(v).swap(v); 

Lo scambio dei contenuti con un altro vettore scambia la capacità.

std::vector<T>(v).swap(v); ==> is equivalent to 

std::vector<T> tmp(v); // copy elements into a temporary vector 
     v.swap(tmp);    // swap internal vector data 

Swap() cambierebbe solo la struttura interna dei dati.

+2

Sì, questa è essenzialmente una copia. AFAIK questo è l'unico modo standard per fare ciò che l'OP vuole. Per quanto riguarda un modo non standard che evita la copia (che l'OP troverà accettabile), non sono sicuro che l'STL di GCC abbia questo (ma non ne sarei sorpreso se lo facesse). –

+0

Michael, dubito che sia garantito dallo standard per funzionare. – avakar

+3

@avakar - sì, questo è garantito per funzionare secondo lo standard (vedi l'analisi di ciò che sta accadendo). ma è anche garantito di copiare tutti gli elementi del vettore originale. –

6

La soluzione idiomatica è scambiare con un vettore di nuova costruzione.

vector<int>().swap(v); 

Modifica: ho letto male la domanda. Il codice sopra cancellerà il vettore. OP vuole mantenere gli elementi inalterati, si restringono solo da capacity() a size().

È difficile dire se il codice di AJ lo farà. Dubito che ci sia una soluzione portatile. Per gcc, dovrai dare un'occhiata alla loro particolare implementazione di vector.

modifica: Così ho dato un'occhiata all'implementazione di libstdC++. Sembra che la soluzione di Aj funzionerà davvero.

vector<int>(v).swap(v); 

Vedi the source, linea 232.

+1

Nota: questo rilascia la memoria per il vettore, ma rimuove anche * tutti * gli elementi (dato che stai scambiando con un vettore temporaneo vuoto). –

13

andare a vedere Scott Meyers efficace elemento STL 17.

In pratica non è possibile ridurre direttamente la dimensione di uno std :: vector stoccaggio. Ridimensiona e reseve non ridurranno mai l'ingombro di memoria di un contenitore. Il "trucco" è creare un nuovo contenitore della giusta dimensione, copiare i dati e scambiare quello con il contenitore corrente. Se vorremmo cancellare un contenitore fuori questo è semplicemente:

std::vector<T>().swap(v); 

Se dobbiamo copiare i dati oltre quindi dobbiamo fare la copia:

std::vector<T>(v).swap(v); 

Quello che fa è crea un nuovo vector con i dati da quello vecchio, facendo la copia che sarebbe richiesta in ogni operazione che abbia l'effetto che ti serve. Quindi chiamare lo scambio semplicemente scambierà i buffer interni tra gli oggetti. Alla fine della linea il vettore temporaneo che è stato creato viene cancellato, ma ha il coraggio del vecchio vettore e il vecchio vettore ha il coraggio della nuova copia che è la dimensione esatta di cui abbiamo bisogno.

2

Non sto dicendo che GCC non potrebbe avere un metodo per fare ciò che vuoi senza una copia, ma sarebbe difficile da implementare (credo) perché i vettori devono usare un oggetto Allocator per allocare e deallocare la memoria e l'interfaccia per un Allocator non include un metodo reallocate().Non penso che sarebbe impossibile da fare, ma potrebbe essere difficile.

+0

Penso che sarebbe impossibile per il contenitore vettoriale, dal momento che gli elementi devono essere contenti in memoria. Non mi sono reso conto che gli allocatori avevano solo .allocate() e .deallocate(), quindi suppongo che questo sia il motivo per cui tale funzionalità non esiste. – ynimous

+1

La funzione realloc() è semplice in C, ma quando si inizia ad aggiungere più semantica all'assegnazione della memoria diventa più complicata. Penso che questo sia il motivo per cui non esiste alcuna controparte in C++. –

3

No, non è possibile ridurre la capacità di un vettore senza copiare. Tuttavia, è possibile controllare la crescita della nuova allocazione controllando capacity() e call reserve() ogni volta che si inserisce qualcosa. Il comportamento predefinito per std :: vector è di aumentare la sua capacità di un fattore 2 ogni volta che è necessaria una nuova capacità. È possibile la crescita è da soli rapporto di magia:

template <typename T> 
void myPushBack(std::vector<T>& vec, const T& val) { 
    if (vac.size() + 1 == vac.capacity()) { 
     vac.reserve(vac.size() * my_magic_ratio); 
    } 

    vec.push_back(val); 
} 

Se siete in un po 'di tecniche hacky, si può sempre passare nel proprio allocatore e fare tutto ciò che dovete fare per recuperare la capacità inutilizzata.

31

Con C++ 11, è possibile chiamare la funzione membro shrink_to_fit(). La draft standard sezione 23.2.6.2 dice:

shrink_to_fit è una richiesta non vincolante per ridurre capacity()-size(). [Nota: la richiesta non è vincolante per consentire la latitudine per le ottimizzazioni specifiche dell'implementazione . -end nota]

1

Se siete preoccupati per il sovraccarico del vettore allora forse si dovrebbe essere in cerca di utilizzare un altro tipo di struttura dati. Hai detto che una volta che il tuo codice è stato inizializzato, il vettore diventa un processo di sola lettura. Suggerirei di andare con un array aperto che permetterà al programma di decidere la sua capacità al momento della compilazione. O forse una lista collegata sarebbe più adatta alle tue esigenze.
Fammi sapere se ho completamente frainteso quello che stavi ottenendo.

-UBcse

+0

Altre strutture dati hanno un sovraccarico maggiore nel caso in cui si abbiano solo pochi elementi. Se ho un caso in cui ho bisogno di milioni di contenitori. std :: vector in questo caso richiede molto meno memoria. –

0

Prendi il libro "STL efficace" di Scott Myers. Ha un articolo completo per la riduzione della capacità del vettore.

Problemi correlati