Подтвердить что ты не робот

С++ - указательный массив в вектор?

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

API, который я использую, дает результат как указатель double*. Я хочу обернуть это типом std::vector<double>.

4b9b3361

Ответ 1

Вы не можете обернуть массив в вектор на месте и ожидать, что вектор будет работать с этим массивом. Лучшее, что вы можете сделать, это предоставить вектор 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, который вы используете, ожидает, что вы освободите память после его использования, вам могут быть интересны интеллектуальные указатели. См. Преторианский ответ.

Ответ 2

Другие предположили, что вы не можете обернуть массив в вектор, но это просто неверно; Подумайте об этом, вектор имеет массив, который лежит в основе контейнера данных! Я пытался делать это время от времени, прежде чем нашел подходящее решение. Предостережение заключается в том, что вы должны обнулять указатели после использования, чтобы избежать двойного освобождения памяти.

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

Ответ 3

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

Это скопирует данные в values в std::vector.

Ответ 4

Другие ответы показывают, как сделать копию возвращаемого массива и создать vector, но при условии, что API выделяет память для массива и ожидает, что вызывающий объект удалит его, вы также можете рассмотреть вопрос о том, чтобы вставить массив в умный указатель и использование его как есть.

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

Вы все еще можете скопировать его в vector, но если вы выполните вышеуказанные шаги, вам не нужно беспокоиться об удалении возвращаемого массива.

Ответ 5

Использовать конструктор векторных итераторов

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

Ответ 6

Спасибо @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);