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.
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.
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;
}
};
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.
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
std::reference_wrapper will also work with std::array. Is this correct?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.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);
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.
std::vectorto 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.double*, or does it take a pointer as an argument and fills it with data?