59
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.

3
  • 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. Commented Sep 2, 2011 at 1:27
  • Does your API function return a double*, or does it take a pointer as an argument and fills it with data? Commented Sep 2, 2011 at 1:55
  • Kerrek SB// good point! something return a double* something take a pointer as an argument. Commented Sep 2, 2011 at 2:23

8 Answers 8

59

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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...
@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.
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.
18

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

1 Comment

This is an excellent answer, but note that it is not portable. This works on Linux with GCC (even all these years later). It doesn't on Windows with MSVC, however. Vector has a completely different internal implementation in that version of STL. I have not yet tried other compilers / contexts. To use this cross platform, plan for it to be in some builds, not all.
9
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.

Comments

7

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.

Comments

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

2 Comments

I presume that using std::reference_wrapper will also work with std::array. Is this correct?
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.
4

Use vector iterator constructor

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

Comments

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

1 Comment

Thank you for drawing attention to the fact one has to rewrite the answer posted by @Ethereal to use his solution on Windows. This code is not however usable against MSVC 2019. I didn't try newer releases, but I doubt they reverted to this being valid. That's not to say that one can't achieve this goal on new versions MSVC..
0

To follow up on @Hamid-Reza-Aarzaghi's Window's answer - that no longer works unfortunately, as vector was redefined in that version of STL again.

I solved the problem (for MSVC) by duplicating the definition of the std:vector, renaming it, and exposed the private member _Mypair publicly. That's that's initial point of entry to get to the rest of the private parts you need to access (in MSVC 2019 at least). I then reinterpret_cast any normal vector pointers into pointers to the custom class, allowing me to achieve the goal.

This is obviously NOT future proof! When upgrading compilers someday, this will more than likely need be rewritten. I DON'T recommend this approach unless you REALLY need a solution for this problem and don't see better alternative.

Btw, I didn't post the source here because it's more than 3k lines! But, you already have the source essentially - simply trace into the vector header on your machine. Then slightly change the names of all the classes (add a prefix or suffix to them). It takes maybe 15 minutes.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.