double * values; // instead of this,
std::vector<double> values; // I want this.
API, который я использую, дает результат как указатель double*
. Я хочу обернуть это типом std::vector<double>
.
double * values; // instead of this,
std::vector<double> values; // I want this.
API, который я использую, дает результат как указатель double*
. Я хочу обернуть это типом std::vector<double>
.
Вы не можете обернуть массив в вектор на месте и ожидать, что вектор будет работать с этим массивом. Лучшее, что вы можете сделать, это предоставить вектор double*
и количество значений, которые будут иметь вектор, сделанный копией каждого элемента и поместив его в себя:
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]
А также, как сказал Преториан, если API, который вы используете, ожидает, что вы освободите память после его использования, вам могут быть интересны интеллектуальные указатели. См. Преторианский ответ.
Другие предположили, что вы не можете обернуть массив в вектор, но это просто неверно; Подумайте об этом, вектор имеет массив, который лежит в основе контейнера данных! Я пытался делать это время от времени, прежде чем нашел подходящее решение. Предостережение заключается в том, что вы должны обнулять указатели после использования, чтобы избежать двойного освобождения памяти.
#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 );
}
В качестве альтернативы вы можете просто создать класс, который наследуется от вектора и обнуляет указатели при уничтожении:
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;
}
};
const int N = 10; // Number of elements in your array
std::vector<double> vec_values(values, values + N);
Это скопирует данные в values
в std::vector
.
Другие ответы показывают, как сделать копию возвращаемого массива и создать vector
, но при условии, что API выделяет память для массива и ожидает, что вызывающий объект удалит его, вы также можете рассмотреть вопрос о том, чтобы вставить массив в умный указатель и использование его как есть.
int numValues;
std::unique_ptr<double[]> values( apiFunction( &numValues ) );
Вы все еще можете скопировать его в vector
, но если вы выполните вышеуказанные шаги, вам не нужно беспокоиться об удалении возвращаемого массива.
Использовать конструктор векторных итераторов
std::vector<int> value_vec (value, value + n); //suppose value has n elements
Спасибо @Ethereal за отличное решение и более полный ответ:
этот код не будет компилироваться в визуальном c++ (возможно, в GCC) из-за различий в реализации std, но с некоторыми изменениями он будет работать отлично.
этот код проверен в 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();
}
ВНИМАНИЕ:
но вы должны заметить, что вы можете заключить указатель массива в std :: vector, только если этот указатель размещен в куче (например, с помощью нового ключевого слова), потому что std :: vector пытается удалить указатель в своем деструкторе, и если указатель массива расположен в стеке, это приведет к двойному удалению одного и того же адреса памяти, и это вызовет ошибку времени выполнения.
так что вы не должны оборачивать указатель массива в стек
int tests[3];
tests[0] = 100; tests[1] = 200; tests[2] = 300;
std::vector<int> targetVector = wrapArrayInVector(tests, 3);