2009-11-14 15 views
46

Me gustaría poder convertir entre std :: vector y su matriz C subyacente int * sin copiar explícitamente los datos.Conversión entre C++ std :: vector y C array sin copiar

¿std :: vector proporciona acceso a la matriz C subyacente? Busco algo como esto

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

EDIT:

Además, es posible hacer lo contrario, es decir, ¿cómo iba a inicializar un std::vector de una matriz C sin copiar?

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

Hay un 'problema' con esto: int pv [4] = {4, 4, 4, 4}; vector v (pv); en realidad copia los contenidos de pv en v ... solo tiene que tener en cuenta que – fho

Respuesta

77

, usted puede obtener un puntero al primer elemento de la siguiente manera:

int* pv = &v[0]; 

Este puntero sólo es válida siempre y cuando el vector no se reasigna. Reasignación pasa automáticamente al insertar más elementos que se ajuste a la capacidad restante del vector (es decir, si v.size() + NumberOfNewElements > v.capacity(). Puede utilizar v.reserve(NewCapacity) para asegurar el vector tiene una capacidad de al menos NewCapacity.

Asimismo, recuerda que cuando el vector se . destruidos, la matriz subyacente se elimina así

+7

"siempre y cuando no agregue elementos adicionales al vector" - sin reservar espacio primero. Si '' reserve() ', puede agregar elementos hasta la capacidad que reservó y garantizar que las referencias y los iteradores sigan siendo válidos. –

+2

@Steve: Buen punto. ¡Solo asegúrese de reservar() antes de obtener el puntero! :) –

+0

@Steve: Es cierto, aunque creo que me resultaría un poco desconcertante si veo código insertando elementos en un vector _y_ utilizando punteros a elementos en el vector que se obtuvieron antes de la inserción. Aún así, modifiqué ese párrafo para intentar y establecer más claramente cuándo ocurre la reasignación. –

19
int* pv = &v[0] 

Tenga en cuenta que esto es sólo el caso de std::vector<>, no se puede hacer lo mismo con otros contenedores estándar.

Scott Meyers cubre este tema extensamente en sus libros.

+2

Creo que incluso está garantizado que funciona de acuerdo con la norma. – Omnifarious

+0

"no se puede hacer lo mismo con otros contenedores estándar" - IIRC podrá hacerlo con cadenas en C++ 0x, y en la práctica casi todas las implementaciones garantizan que el almacenamiento de cadenas sea contiguo. –

+3

Puede obtener una matriz de solo lectura que contenga los elementos de 'std :: string' utilizando sus miembros' c_str() 'o' data() '.Debido a esto, aunque el estándar no requiere que las cadenas se almacenen contiguamente en la memoria, sería muy extraño e ineficaz no hacerlo. –

14

Si usted tiene condiciones muy controladas, que sólo puede hacer:

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

se advirtió que esto sólo funcionará siempre y cuando el vector no tiene que crecer, y el vector todavía gestionará el curso de la vida de la matriz subyacente (es decir, no eliminar pv). Esto no es algo raro de hacer cuando se llama a C API subyacentes, pero generalmente se hace con un temporal sin nombre en lugar de crear una variable int * explícita.

0

Una forma de protegerse contra los cambios de tamaño es reservar el espacio máximo (o mayor) que necesitará:

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

Esto asegurará que push_backs ganaron no causa reasignación o f los datos existentes.

15

En C++ 11, puede usar vector::data() para obtener el puntero C array.

Cuestiones relacionadas