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

Un'API che sto utilizzando fornisce un risultato come puntatore double*. Voglio concludere questo con il tipo std::vector<double>.C++ - array di puntatori su Vector?

+1

Ricordate che è possibile ottenere 'std :: VECTOR' per copiare gli elementi restituiti dal array come mostrato di seguito, ma se questa API si aspetta che tu chiami un'altra funzione per liberare la memoria allocata per l'array o per eliminare l'array tu stesso, devi farlo. La creazione del vettore non libererà quella memoria. – Praetorian

+0

La funzione API * restituisce * a 'double *', oppure accetta un puntatore come * argomento * e lo riempie di dati? –

+0

Kerrek SB // buon punto! qualcosa restituisce un doppio * qualcosa prende un puntatore come argomento. – webnoon

risposta

23

Non è possibile racchiudere una matrice in un vettore in posizione e prevedere che il vettore funzioni su tale matrice. Il meglio che puoi fare è dare il vettore del double* e il numero di valori, che avrà il vettore di fare una copia di ogni elemento e lo mise in sé:

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] 

E anche, come Pretorio ha detto, se il L'API che stai usando si aspetta che tu possa liberare la memoria dopo averla usata, potresti essere interessato a puntatori intelligenti. Vedi Praetorian's answer.

+3

Domanda semplice con forse una risposta complessa: PERCHÉ non c'è modo di avvolgere un vettore STL attorno a un esistente matrice semplice (sul posto)? È perché STL presuppone che la dimensione riservata sia una potenza di 2? Altrimenti non vedo un motivo al momento perché questo non dovrebbe essere possibile ... –

+2

@JakobS. perché il vettore insiste nel controllare l'allocazione e la riallocazione della sua memoria.Le garanzie fatte dalle funzioni dei membri non potevano essere mantenute se il vettore non poteva controllare la matrice sottostante. –

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

Questo copierà i dati in values ad un std::vector.

+1

'values' è un' double * ', non un' double [] ', quindi' sizeof (valori) == sizeof (double *) ', non il numero di elementi nella matrice. Hai bisogno di 'std :: vector vec_values ​​(valori, valori + numValues)' – Praetorian

+0

@Praetorian: Spiacente, ho dimenticato di apportare questa modifica – Jacob

1

Usa vettore costruttore iterator

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

5

Le altre risposte mostrano come fare una copia della matrice restituita e creare un vector, ma assumendo l'API alloca la memoria per la matrice e si aspetta che il chiamante da eliminare Si può anche prendere in considerazione l'idea di inserire l'array in un puntatore intelligente e usarlo così com'è.

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

è ancora possibile copiare questo in un vector ma se fate i passaggi precedenti non devi più preoccuparti di eliminare la matrice restituita.

6

Questa è probabilmente la risposta che stai cercando. Altri hanno suggerito che non è possibile racchiudere un array in un vettore, ma semplicemente non è vero; pensaci, un vettore ha una matrice come contenitore di dati sottostante! Avevo tentato questo e quello per un po 'di tempo prima di trovare una soluzione praticabile. L'avvertenza è che è necessario azzerare i puntatori dopo l'uso al fine di evitare il doppio liberare 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); 
} 

In alternativa si può solo fare una classe che eredita da vettoriale e nulli i puntatori su di distruzione:

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; 
    } 
};