53
double * values; // instead of this,
std::vector<double> values; // I want this.

An API I'm using provides a result as double* pointer. I want to wrap this with the std::vector<double> type.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
webnoon
  • 945
  • 3
  • 9
  • 18
  • 1
    Remember that you can get `std::vector` to copy the elements returned from the array as shown below, but if this API expects you to call another function to free memory allocated for the array, or delete the array yourself, you must do that. Creating the vector will not free that memory. – Praetorian Sep 02 '11 at 01:27
  • Does your API function *return* a `double*`, or does it take a pointer as an *argument* and fills it with data? – Kerrek SB Sep 02 '11 at 01:55
  • Kerrek SB// good point! something return a double* something take a pointer as an argument. – webnoon Sep 02 '11 at 02:23

7 Answers7

54

You can't wrap an array in a vector in place and expect the vector to operate on that array. The best you can do is give the vector the double* and the number of values, which will have the vector make a copy of every element and put it in itself:

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]

And also, like Praetorian said, if the API you are using expects you to free the memory after using it, you might be interested in smart pointers. See Praetorian's answer.

Community
  • 1
  • 1
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • 5
    Simple question with maybe a complex answer: WHY is there no way to wrap an STL vector around an existing plain array (in place) ? Is it because STL assumes that the reserved size is a power of 2? Otherwise I don't see a reason at the moment why this should not be possible... – Jakob S. Dec 17 '12 at 14:32
  • 8
    @JakobS. because the vector insists on controlling the allocation and reallocation of its memory. The guarantees made by member functions couldn't hold if the vector couldn't control the underlying array. – Seth Carnegie Dec 17 '12 at 16:31
  • can anybody point to where this particular vector constructor is defined in the documentation? I see a bunch of constructors but I don't understand which one this is. – karobar Jul 01 '21 at 16:08
17

Others have suggested that you cannot wrap an array in a vector, but that's simply not true; think about it, a vector has an array as it's underlying data container! I had been attempting this off and on for quite some time before I came up with a workable solution. The caveat is that you have got to zero out the pointers after use in order to avoid double-freeing the memory.

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

Alternatively you could just make a class that inherits from vector and nulls out the pointers upon destruction:

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;
  }   
};  
Ethereal
  • 2,604
  • 1
  • 20
  • 20
8
const int N = 10; // Number of elements in your array
std::vector<double> vec_values(values, values + N);

This will copy the data in values to a std::vector.

Jacob
  • 34,255
  • 14
  • 110
  • 165
5

If using C++11, you could use a std::vector<std::reference_wrapper<double>>.

#include <functional> // std::reference_wrapper
#include <vector>

#include <iostream>
#include <numeric> // std::iota
#include <random> // std::mt19937
#include <algorithm> // std::shuffle

int main() {
const int N = 10; // Number of elements in your array
double values[N];
std::iota(values, values+N, -4.0);

std::vector<std::reference_wrapper<double>> v(values, values + N);
std::shuffle(v.begin(), v.end(), std::mt19937{std::random_device{}()});

std::cout << "Contents of the array: ";
for(auto i=0; i < N; ++i) std::cout << values[i] << ' ';
std::cout << '\n';

std::cout << "Contents of the array, shuffled: ";
for(auto i: v) std::cout << i << ' ';
std::cout << '\n';

std::cout << "Change values using the vector shuffled\n";
auto j = 44.;
for(double& i: v) i = ++j;

std::cout << "Contents of the array, shuffled: ";
for(auto i: v) std::cout << i << ' ';
std::cout << '\n';
    
std::cout << "Contents of the array: ";
for(auto i=0; i < N; ++i) std::cout << values[i] << ' ';
std::cout << '\n';
}

Possible output:

Contents of the array: -4 -3 -2 -1 0 1 2 3 4 5 
Contents of the array, shuffled: 1 3 -2 0 -3 5 -4 4 -1 2 
Change values using the vector shuffled
Contents of the array, shuffled: 45 46 47 48 49 50 51 52 53 54 
Contents of the array: 51 49 47 53 48 45 54 46 52 50

pro: zero copy

ref: https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper

Mizux
  • 8,222
  • 7
  • 32
  • 48
  • I presume that using `std::reference_wrapper` will also work with `std::array`. Is this correct? – Bart Aug 11 '21 at 09:39
  • If ```values``` were dynamically allocated, does vector ```v``` gain ownership of the underlying array? This is not clear. If not, I think it's unsafe. Or maybe you can just use a ```std::unique_ptr``` before declaring ```v```. – Breno May 08 '23 at 07:12
5

The other answers show how to make a copy of the returned array and create a vector, but assuming the API allocates memory for the array and expects the caller to delete it, you may also want to consider sticking the array into a smart pointer and using it as is.

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

You can still copy this into a vector but if you do the above steps you don't have to worry about deleting the returned array.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
3

Use vector iterator constructor

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

ChanDon
  • 391
  • 1
  • 5
  • 15
2

Thanks to @Ethereal for the nice solution and to make his/her answer more complete:

that code will not compile in visual c++ (maybe will in GCC) because of differences in the std implementation but with some changes, it will work perfectly.

this code tested in Microsoft Visual C++ (VS2015):

#include <iostream>
#include <vector>

template<typename T> std::vector<T> wrapArrayInVector(T* sourceArray, size_t arraySize) {
    std::vector<T> targetVector;
    std::vector<T>::_Mybase* basePtr{ (std::vector<T>::_Mybase*)((void*)&targetVector) };
    basePtr->_Get_data()._Myfirst = sourceArray;
    basePtr->_Get_data()._Mylast = basePtr->_Get_data()._Myend = basePtr->_Get_data()._Myfirst + arraySize;
    return targetVector;
}

int main() {
    int* tests{ new int[3] };
    tests[0] = 100; tests[1] = 200; tests[2] = 300;
    std::vector<int> targetVector{ wrapArrayInVector(tests, 3) };
    std::cout << std::hex << &tests[0] << ": " << std::dec
    << tests[0] << " " << tests[1] << " " << tests[2] << std::endl;
    std::cout << std::hex << &targetVector[0] << ": " << std::dec
    << targetVector[0] << " " << targetVector[1] << " " << targetVector[2] << std::endl;
    std::cin.get();
}

CAUTION:

but you should be noticed you can wrap an array pointer in std::vector just if that pointer is allocated in heap(for example using new keyword) because std::vector is trying to delete the pointer in its destructor, and if array pointer is allocated on the stack it will cause double delete same memory address and it will cause run time error.

so you must not wrap stack allocated array pointer like this

int tests[3];
tests[0] = 100; tests[1] = 200; tests[2] = 300;
std::vector<int> targetVector = wrapArrayInVector(tests, 3);