std :: vector contro std :: array in C ++


283

Qual è la differenza tra a std::vectore an std::arrayin C ++? Quando uno dovrebbe essere preferito su un altro? Quali sono i pro ed i contro di ognuno? Tutto il mio libro di testo fa è elencare come sono uguali.


1
Sto cercando un confronto tra std::vectorvs. std::arraye come i termini sono diversi.
Zud,

Zud, std::arraynon è lo stesso di un array C ++. std::arrayè un wrapper molto sottile attorno agli array C ++, con lo scopo principale di nascondere il puntatore all'utente della classe. Aggiornerò la mia risposta.
ClosureCowboy,

Ho aggiornato il titolo e il testo della domanda per riflettere il tuo chiarimento.
Matteo Italia,

Risposte:


318

std::vectorè una classe modello che incapsula un array dinamico 1 , memorizzato nell'heap, che cresce e si restringe automaticamente se gli elementi vengono aggiunti o rimossi. Esso fornisce tutti i ganci ( begin(), end(), iteratori, ecc), che lo rendono funzionano bene con il resto del STL. Ha anche diversi metodi utili che ti consentono di eseguire operazioni che su un array normale sarebbero ingombranti, come ad esempio l'inserimento di elementi nel mezzo di un vettore (gestisce tutto il lavoro di spostamento dei seguenti elementi dietro le quinte).

Poiché memorizza gli elementi in memoria allocati sull'heap, ha un certo sovraccarico rispetto agli array statici.

std::arrayè una classe modello che incapsula un array di dimensioni statiche, memorizzato all'interno dell'oggetto stesso, il che significa che, se si crea un'istanza della classe nello stack, l'array stesso sarà nello stack. Le sue dimensioni devono essere conosciute al momento della compilazione (viene passata come parametro del modello) e non può crescere o ridursi.

È più limitato di std::vector, ma spesso è più efficiente, soprattutto per le piccole dimensioni, perché in pratica è principalmente un involucro leggero attorno a un array in stile C. Tuttavia, è più sicuro, poiché la conversione implicita in puntatore è disabilitata e fornisce gran parte delle funzionalità relative a STL di std::vectore degli altri contenitori, quindi puoi usarla facilmente con gli algoritmi STL & co. Comunque, proprio per la limitazione delle dimensioni fisse è molto meno flessibile di std::vector.

Per un'introduzione a std::array, dai un'occhiata a questo articolo ; per una rapida introduzione std::vectore le operazioni che sono possibili su di essa, ti consigliamo di consultare la sua documentazione .


  1. In realtà, penso che nello standard siano descritti in termini di massima complessità delle diverse operazioni (ad es. Accesso casuale in tempo costante, iterazione su tutti gli elementi in tempo lineare, aggiunta e rimozione di elementi alla fine in tempo ammortizzato costante, ecc.), ma AFAIK non esiste altro metodo per soddisfare tali requisiti se non quello di utilizzare un array dinamico. Come affermato da @Lucretiel, lo standard in realtà richiede che gli elementi siano archiviati in modo contiguo, quindi è un array dinamico, archiviato dove l'allocatore associato lo colloca.

6
Per quanto riguarda la tua nota a piè di pagina: se vero, lo standard garantisce anche che l'aritmetica del puntatore sugli elementi interni funziona, il che significa che deve essere un array: & vec [9] - & vec [3] == 6 è vero.
Lucretiel

9
Sono abbastanza sicuro che quel vettore non si riduca automaticamente, ma dal C ++ 11 puoi chiamare shrink_to_fit.
Dino,

Sono totalmente confuso dal termine array statico e non sono sicuro di quale sia la terminologia corretta. Intendi un array di dimensioni statiche e non un array di variabili statiche (uno che utilizza una memoria statica). stackoverflow.com/questions/2672085/… . Qual è la terminologia corretta? Matrice statica è un termine sciatto per una matrice di dimensioni fisse?
Bosone Z,

3
@Zboson: sicuramente non sei solo tu, statico è un termine piuttosto abusato; la stessa staticparola chiave in C ++ ha tre diversi significati non correlati e il termine è spesso usato anche per parlare di cose che sono state corrette al momento della compilazione. Spero che "di dimensioni statiche" sia un po 'più chiaro.
Matteo Italia,

3
Una cosa da notare: Per la programmazione in tempo reale (in cui non si dovrebbe avere alcuna allocazione dinamica / deallocazione dopo l'avvio) std :: array di sarebbe probabilmente preferibile rispetto std :: vector.
TED

17

Utilizzando la std::vector<T>classe:

  • ... è veloce come usare gli array incorporati, supponendo che tu stia facendo solo le cose che gli array incorporati ti consentono di fare (leggi e scrivi su elementi esistenti).

  • ... si ridimensiona automaticamente quando vengono inseriti nuovi elementi.

  • ... ti permette di inserire nuovi elementi all'inizio o nel mezzo del vettore, spostando automaticamente il resto degli elementi "su" (ha senso?). Ti consente di rimuovere elementi ovunque std::vectoranche in, spostando automaticamente il resto degli elementi verso il basso.

  • ... consente di eseguire una lettura con controllo dell'intervallo con il at()metodo (è sempre possibile utilizzare gli indicizzatori []se non si desidera che questo controllo venga eseguito).

Ci sono due tre avvertenze principali da usare std::vector<T>:

  1. Non si dispone di un accesso affidabile al puntatore sottostante, il che può costituire un problema se si ha a che fare con funzioni di terze parti che richiedono l'indirizzo di un array.

  2. La std::vector<bool>classe è sciocca. È implementato come un bitfield condensato, non come un array. Evitalo se vuoi una serie di bools!

  3. Durante l'utilizzo, std::vector<T>s sarà un po 'più grande di un array C ++ con lo stesso numero di elementi. Questo perché hanno bisogno di tenere traccia di una piccola quantità di altre informazioni, come la loro dimensione attuale, e perché ogni volta std::vector<T>che si ridimensionano, riservano più spazio di quello di cui hanno bisogno. Questo per impedire loro di dover ridimensionare ogni volta che viene inserito un nuovo elemento. Questo comportamento può essere modificato fornendo un'usanza allocator, ma non ho mai sentito il bisogno di farlo!


Modifica: dopo aver letto la risposta di Zud alla domanda, ho sentito che avrei dovuto aggiungere questo:

La std::array<T>classe non è la stessa di un array C ++. std::array<T>è un wrapper molto sottile attorno alle matrici C ++, con lo scopo principale di nascondere il puntatore all'utente della classe (in C ++, le matrici sono implicitamente espresse come puntatori, spesso con effetto sconcertante). La std::array<T>classe memorizza anche le sue dimensioni (lunghezza), che può essere molto utile.


5
È "altrettanto veloce" rispetto all'utilizzo di un array integrato allocato dinamicamente. D'altro canto, l'utilizzo di un array automatico potrebbe avere prestazioni notevolmente diverse (e non solo durante l'allocazione, a causa degli effetti della località).
Ben Voigt

4
Per i vettori non bool in C ++ 11 e versioni successive, è possibile chiamare data()a std::vector<T>per ottenere il puntatore sottostante. Puoi anche semplicemente prendere l'indirizzo dell'elemento 0 (garantito per funzionare con C ++ 11, probabilmente funzionerà con le versioni precedenti).
Matt,

16

Per sottolineare un punto sollevato da @MatteoItalia, la differenza di efficienza è dove sono archiviati i dati. La memoria heap (richiesta con vector) richiede una chiamata al sistema per allocare memoria e questo può essere costoso se si contano i cicli. La memoria dello stack (possibile per array) è praticamente "zero overhead" in termini di tempo, poiché la memoria viene allocata semplicemente regolando il puntatore dello stack e viene eseguita una sola volta all'entrata in una funzione. Lo stack evita anche la frammentazione della memoria. A dire il std::arrayvero , non sarà sempre in pila; dipende da dove lo si assegna, ma implicherà comunque un'allocazione di memoria in meno dall'heap rispetto al vettore. Se hai un

  • piccolo "array" (sotto 100 elementi dicono) - (uno stack tipico è di circa 8 MB, quindi non allocare più di qualche KB nello stack o meno se il codice è ricorsivo)
  • la dimensione sarà fissa
  • la durata è nell'ambito della funzione (o è un valore membro con la stessa durata della classe genitore)
  • stai contando i cicli,

sicuramente usare un std::arrayover un vettore. Se uno di questi requisiti non è vero, utilizzare a std::vector.


3
Bella risposta. "A dire il vero, std :: array non sarà sempre nello stack; dipende da dove lo si alloca" Quindi come potrei creare uno std :: array non nello stack con un gran numero di elementi?
Trilarion,

4
@Trilarion usa new std::arrayo lo rende un membro di una classe che usi 'new` per allocare.
Mark Lakata,

Quindi questo significa che new std::arraysi aspetta ancora di conoscerne le dimensioni al momento della compilazione e non può cambiarle ma vive ancora nell'heap?
Trilarion,

Sì. Non c'è un significativo vantaggio di utilizzare new std::arrayvs new std::vector.
Mark Lakata,

12

Se stai pensando di utilizzare array multidimensionali, allora c'è un'ulteriore differenza tra std :: array e std :: vector. Un array std :: multidimensionale avrà gli elementi imballati in memoria in tutte le dimensioni, proprio come lo è un array in stile ac. Uno std :: vector multidimensionale non verrà impacchettato in tutte le dimensioni.

Date le seguenti dichiarazioni:

int cConc[3][5];
std::array<std::array<int, 5>, 3> aConc;
int **ptrConc;      // initialized to [3][5] via new and destructed via delete
std::vector<std::vector<int>> vConc;    // initialized to [3][5]

Un puntatore al primo elemento nell'array c-style (cConc) o std :: array (aConc) può essere ripetuto attraverso l'intero array aggiungendo 1 a ciascun elemento precedente. Sono ben confezionati.

Un puntatore al primo elemento nell'array vettoriale (vConc) o nell'array di puntatori (ptrConc) può essere iterato solo attraverso i primi 5 (in questo caso) elementi, quindi ci sono 12 byte (sul mio sistema) di overhead per il prossimo vettore.

Ciò significa che un array std :: vector> inizializzato come un array [3] [1000] sarà molto più piccolo in memoria di un array inizializzato come un array [1000] [3], ed entrambi saranno più grandi nella memoria di uno std: matrice allocata in entrambi i modi.

Questo significa anche che non puoi semplicemente passare un array vettoriale (o puntatore) multidimensionale a, diciamo, openGL senza tenere conto del sovraccarico di memoria, ma puoi passare ingenuamente un array std :: array multidimensionale a openGL e farlo funzionare.


-17

Un vettore è una classe contenitore mentre un array è una memoria allocata.


23
La tua risposta sembra indirizzare std::vector<T>contro T[], ma la domanda riguarda std::vector<T>versus std::array<T>.
Keith Pinson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.