2009-11-14 21 views
46

Mi piacerebbe essere in grado di convertire tra std :: vector e il suo array C sottostante int * senza copiare esplicitamente i dati.Conversione tra C++ std :: vector e array C senza copiare

std :: vector fornisce l'accesso all'array C sottostante? Sto cercando qualcosa di simile

vector<int> v (4,100) 
int* pv = v.c_array(); 

EDIT:

Inoltre, è possibile fare il contrario, vale a dire come faccio a inizializzare un std::vector da una matrice C senza copiare?

int pv[4] = { 4, 4, 4, 4}; 
vector<int> v (pv); 
+0

C'è un 'problema' con questo: int pv [4] = {4, 4, 4, 4}; vettore v (pv); copia effettivamente il contenuto di pv in v ... devi solo essere a conoscenza di quello – fho

risposta

77

è possibile ottenere un puntatore al primo elemento come segue:

int* pv = &v[0]; 

Questo puntatore è valida solo fino a quando il vettore non è riallocato. Ridistribuzione avviene automaticamente se si inserisce più elementi che si inserisce nella capacità residua del vettore (cioè, se v.size() + NumberOfNewElements > v.capacity(). È possibile utilizzare v.reserve(NewCapacity) per garantire il vettore ha una capacità di almeno NewCapacity.

Ricorda anche che quando il vettore diventa . distrutta, la matrice sottostante viene eliminato così

+7

"finché non si aggiungono elementi aggiuntivi al vettore" - senza prima riservare spazio. Se si 'reserve()', quindi è possibile aggiungere elementi fino alla capacità che hai riservato e garantire che i riferimenti e gli iteratori siano ancora validi. –

+2

@Steve: buon punto. Assicurati di prenotare() prima di ottenere il puntatore! :) –

+0

@Steve: È vero, anche se penso che troverei un po 'sconcertante se vedessi il codice inserire elementi in un vettore _e_ usando i puntatori agli elementi nel vettore che sono stati ottenuti prima dell'inserimento. Tuttavia, ho modificato quel paragrafo per provare e dichiarare più chiaramente quando avviene la riallocazione. –

19
int* pv = &v[0] 

Si noti che questo è solo il caso di std::vector<>, non si può fare lo stesso con altri contenitori standard.

Scott Meyers tratta ampiamente questo argomento nei suoi libri.

+2

Credo che questo sia garantito anche per funzionare secondo lo standard. – Omnifarious

+0

"non si può fare lo stesso con altri contenitori standard" - IIRC si sarà in grado di farlo con stringhe in C++ 0x, e praticamente praticamente ogni implementazione garantisce effettivamente che lo storage della stringa sia contiguo. –

+3

Puoi ottenere un array di sola lettura contenente gli elementi di un 'std :: string' usando i suoi membri' c_str() 'o' data() '.Per questo motivo, mentre lo standard non richiede che le stringhe vengano memorizzate in modo contiguo nella memoria, sarebbe molto strano e inefficiente non farlo. –

14

Se si è molto condizioni controllate, si può solo fare:

std::vector<int> v(4,100); 
int* pv = &v[0]; 

Sappiate che questo funziona solo fino a quando il vettore non ha bisogno di crescere, e il vettore sarà ancora la gestione del ciclo di vita dell'array sottostante (vale a dire, non eliminare pv). Questa non è una cosa insolita da fare quando si chiamano le API C sottostanti, ma di solito si fa con un temporaneo senza nome piuttosto che creando una variabile int * esplicita.

0

Un modo per proteggersi contro i cambiamenti dimensione è di riservare lo spazio massimo (o più grande) che avrete bisogno di:

std::vector<int> v(4,100); //Maybe need 
v.reserve(40);    //reallocate to block out space for 40 elements 

Questo farà sì che push_backs vinto causano la riallocazione o f i dati esistenti.

15

In C++ 11, è possibile utilizzare vector::data() per ottenere il puntatore dell'array C.

Problemi correlati