2015-08-07 25 views
12

Normalmente chiamo reserve su un std::vector subito dopo la sua costruzione. Ciò non dovrebbe in genere causare la distruzione dell'archiviazione esistente dello std::vector e sostituirla con una nuova? C'è un modo per riservare la memoria in fase di costruzione piuttosto che allocare lo spazio heap e quindi distruggerlo immediatamente? Oppure esiste un trucco di implementazione all'interno dello std::vector per garantire che questo non sia un problema?Come riservo la memoria per un vettore std :: al momento della costruzione?

I costruttori disponibili sembrano essere in grado di essere utili per riempire i valori con std::vector anziché riservare spazio esplicitamente.

+10

Perché pensi che non v'è alcun stanziamento mucchio esistente su un vettore fresco? –

+4

cosa c'è di sbagliato nel chiamare 'reserve()' nel corpo del costruttore? sembra che tu stia cercando di fare un'ottimizzazione micro –

+1

Penso che 'std :: vector v; std :: cout << v.capacity(); 'è garantito per stampare' 0', almeno [gcc lo fa] (http://coliru.stacked-crooked.com/a/9ae2c73e77f0d5af), il che significa che c'è nessuna allocazione dell'heap per il costruttore * default *. – Nawaz

risposta

9

La tua domanda si basa su una premessa errata, ovvero che uno std::vector<T> predefinito creerà un'allocazione [a lunghezza zero].

Non c'è letteralmente alcun motivo per farlo. Un vettore fresco dovrebbe avere la capacità zero (sebbene ciò sia richiesto dalla sanità mentale, non dallo standard).

Come tale, il tuo obiettivo è già intrinsecamente soddisfatto.

Per essere sincero, la libreria standard non è del tutto che stupido.

+2

+1. Per quanto riguarda l'ultima frase: direi anche che la libreria standard (in particolare la sua parte relativa a 11 +) è progettata e implementata in modo molto intelligente. Non riesco a capire perché così tante persone pensano, che possono fare molto meglio e provare a scrivere tutto da zero ... Mi sto ammalando quando vedo un altro * "Sto scrivendo un motore di gioco e questo è il mio vettore personalizzato/string/quant'altro.Perché non funziona? "* ... –

+0

@MateuszGrzejek: Oltre a" boost :: bimap' (che trovo completamente inestimabile) non riesco a ricordare l'ultima volta che ho risolto un problema di archiviazione usando qualsiasi cosa non dalla libreria standard. :) –

+0

Ah, il mio male: http://stackoverflow.com/questions/8190950/may-stdvector-make-use-of-small-buffer-optimization – ecatmur

0

Se il numero di elementi è noto al momento della compilazione da voi, è possibile elencare-inizializzare il vettore con questi elementi:

class MyClass 
{ 
     int x, y, z; 
     std::vector<int> v; 

    public: 
     MyClass(int X, int Y, int Z) : x(X), y(Y), z(Z), v{x, y, z} 
     {} 
}; 

Ma questo non è molto bello da mantenere. Esistono tecniche più avanzate, come gli allocatori personalizzati, che è possibile utilizzare per fare in modo che lo std::vector utilizzi la memoria da un pool di memoria pre-allocato, ad esempio: dubito che sia davvero necessario. Le moderne implementazioni potrebbero ottimizzare facilmente un problema così semplice.

-1

L'oggetto   std::vector e la sua matrice di elementi non esistono sullo stesso blocco di memoria contigua, altrimenti il ​​suo indirizzo cambierà ogni volta che ridimensioni l'array, rendendo impossibile mantenere un riferimento affidabile di esso. Il corpo principale dell'oggetto contiene solo variabili di controllo e un puntatore all'array effettivo, e sarà istanziato nello stack (supponendo che lo si utilizzi come variabile locale) insieme alle altre variabili locali. E in questo momento la matrice sarà vuota e probabilmente rappresentata da un puntatore a nullptr. Quindi non importa se hai reserve in fase di costruzione o subito dopo, non si verificherà alcun evento di ottimizzazione significativo.

Se si desidera un std::vector con dimensioni statiche riservate all'istante, è sufficiente utilizzare un normale array C anziché std::vector. Assicurati che si adatti allo stack.

+1

_ "sarà istanziato nello stack" _ Come lo sai? 'static std :: vector v1; auto v2p = std :: make_unique >(); 'Whoops ... –

+0

@LightnessRacesinOrbit Supponendo che lo sta usando normalmente, come in una funzione. – Havenard

+3

Questa è una supposizione enorme da fare. Perché non parli delle durate dello storage, invece dei dettagli di implementazione arbitrari? Inoltre, non raccomandare i C array; raccomandare 'std :: array'. –

0

Il motivo può essere ironico, stiamo esaurendo la firma della funzione.

Il requisito viene dal usando scenario che abbiamo esattamente sapere quanti elementi ci farà risparmiare in vettore ma davvero non mi piace il n-duplicato elementi costruttore:

std::vector(size_type count, const T& value = T()) 

Purtroppo la firma è occupato dal costruttore di cui sopra. Qualsiasi altra possibile firma potrebbe causare problemi. Per esempio.

  1. vector(size_type count, size_type reserve_count) i conflitti con sopra n elementi-duplicato di costruzione per vettore di T(size_type).

  2. vector(size_type count, const T& value = T(), size_type reserve_count) è una soluzione possibile ma è troppo lunga e ancora noiosa. Abbiamo bisogno di costruire un valore di default non usiamo mai durante la chiamata auto v = vector<T>(0, T(), reserve_count)

Altre soluzioni possibili:

  1. fornisce una funzione simile make_pair/make_unique.

  2. Definisce un Reserver, che deriva da allocator, in modo che possiamo utilizzare il costruttore vettore (const Allocator & alloc) come

auto v = vector<Type>(new Reserver(reserve_count));