2011-09-02 18 views
19
double * values; // instead of this, 
std::vector<double> values; // I want this. 

Un API que estoy utilizando proporciona un resultado como double* puntero. Quiero envolver esto con el tipo std::vector<double>.C++ - matriz de puntero a Vector?

+1

Recuerde que usted puede conseguir 'std :: vECTOR' para copiar los elementos devueltos por el array como se muestra a continuación, pero si esta API espera que llame a otra función para liberar memoria asignada para la matriz, o eliminar la matriz usted mismo, debe hacerlo. Crear el vector no liberará esa memoria. – Praetorian

+0

¿Su función API * devuelve * un 'doble *', o toma un puntero como * argumento * y lo llena de datos? –

+0

Kerrek SB // ¡buen punto! algo devuelve un doble * algo tomar un puntero como argumento. – webnoon

Respuesta

23

No puede envolver una matriz en un vector en el lugar y esperar que el vector funcione en esa matriz. Lo mejor que puede hacer es dar el vector de la double* y el número de valores, lo que tendrá el vector de hacer una copia de cada elemento y lo puso en sí mismo:

int arrlen = 0; 

// pretending my_api takes arrlen by reference and sets it to the length of the array 
double* dbl_ptr = my_api(arrlen); 

vector<double> values(dbl_ptr, dbl_ptr + arrlen); 

// note that values is *not* using the same memory as dbl_ptr 
// so although values[0] == dbl_ptr[0], &values[0] != &dbl_ptr[0] 

Y también, como pretoriana dijo, si el API que está utilizando espera que libere la memoria después de usarla, puede que le interesen los indicadores inteligentes. Ver Praetorian's answer.

+3

Pregunta simple con una respuesta tal vez compleja: ¿POR QUÉ no hay forma de envolver un vector STL alrededor de un existente matriz simple (en su lugar)? ¿Es porque STL supone que el tamaño reservado es una potencia de 2? De lo contrario, no veo una razón en este momento por la que esto no debería ser posible ... –

+2

@JakobS. porque el vector insiste en controlar la asignación y la reasignación de su memoria.Las garantías hechas por las funciones miembro no podrían mantenerse si el vector no pudiera controlar la matriz subyacente. –

4
const int N = 10; // Number of elements in your array 
std::vector<double> vec_values(values, values + N); 

Esto copiará los datos en values a un std::vector.

+1

'values' es un' double * ', no un' double [] ', así' sizeof (values) == sizeof (double *) ', no la cantidad de elementos en el array. Necesita 'std :: vector vec_values ​​(values, values ​​+ numValues)' – Praetorian

+0

@Praetorian: Lo siento, se olvidó de hacer ese cambio – Jacob

1

uso de vectores constructor iterador

std::vector<int> value_vec (value, value + n); //suppose value has n elements

5

Las otras respuestas muestran cómo hacer una copia de la matriz devuelta y crear un vector, pero asumiendo la API asigna memoria para la matriz y espera que la persona que llama para eliminar es posible que también desee considerar pegar la matriz en un puntero inteligente y usarlo como está.

int numValues; 
std::unique_ptr<double[]> values(apiFunction(&numValues)); 

todavía puede copiar esto en un vector pero si lo hace los pasos anteriores usted no tiene que preocuparse acerca de cómo eliminar la matriz devuelta.

6

Esta es probablemente la respuesta que está buscando. Otros han sugerido que no se puede envolver una matriz en un vector, pero eso simplemente no es cierto; ¡piénselo, un vector tiene una matriz ya que es un contenedor de datos subyacente! Había estado intentando esto sin parar durante bastante tiempo antes de encontrar una solución viable. La advertencia es que tienes que poner a cero los punteros después de su uso para evitar duplicar la memoria.

#include <vector> 
#include <iostream> 

template <class T> 
void wrapArrayInVector(T *sourceArray, size_t arraySize, std::vector<T, std::allocator<T> > &targetVector) { 
    typename std::_Vector_base<T, std::allocator<T> >::_Vector_impl *vectorPtr = 
    (typename std::_Vector_base<T, std::allocator<T> >::_Vector_impl *)((void *) &targetVector); 
    vectorPtr->_M_start = sourceArray; 
    vectorPtr->_M_finish = vectorPtr->_M_end_of_storage = vectorPtr->_M_start + arraySize; 
} 

template <class T> 
void releaseVectorWrapper(std::vector<T, std::allocator<T> > &targetVector) { 
    typename std::_Vector_base<T, std::allocator<T> >::_Vector_impl *vectorPtr = 
     (typename std::_Vector_base<T, std::allocator<T> >::_Vector_impl *)((void *) &targetVector); 
    vectorPtr->_M_start = vectorPtr->_M_finish = vectorPtr->_M_end_of_storage = NULL; 
} 

int main() { 

    int tests[6] = { 1, 2, 3, 6, 5, 4 }; 
    std::vector<int> targetVector; 
    wrapArrayInVector(tests, 6, targetVector); 

    std::cout << std::hex << &tests[0] << ": " << std::dec 
      << tests[1] << " " << tests[3] << " " << tests[5] << std::endl; 

    std::cout << std::hex << &targetVector[0] << ": " << std::dec 
      << targetVector[1] << " " << targetVector[3] << " " << targetVector[5] << std::endl; 

    releaseVectorWrapper(targetVector); 
} 

Alternativamente usted podría hacer una clase que hereda de vectores y nulos los punteros a la destrucción:

template <class T> 
class vectorWrapper : public std::vector<T> 
{ 
public: 
    vectorWrapper() { 
    this->_M_impl _M_start = this->_M_impl _M_finish = this->_M_impl _M_end_of_storage = NULL; 
    } 

    vectorWrapper(T* sourceArray, int arraySize) 
    { 
    this->_M_impl _M_start = sourceArray; 
    this->_M_impl _M_finish = this->_M_impl _M_end_of_storage = sourceArray + arraySize; 
    } 

    ~vectorWrapper() { 
    this->_M_impl _M_start = this->_M_impl _M_finish = this->_M_impl _M_end_of_storage = NULL; 
    } 

    void wrapArray(T* sourceArray, int arraySize) 
    { 
    this->_M_impl _M_start = sourceArray; 
    this->_M_impl _M_finish = this->_M_impl _M_end_of_storage = sourceArray + arraySize; 
    } 
};