C ++ - 指向Vector的指针数组?

时间:2011-09-02 01:16:25

标签: c++

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

我正在使用的API提供了double*指针的结果。我想用std::vector<double>类型包装它。

7 个答案:

答案 0 :(得分:30)

您无法将数组包装在矢量并期望该矢量在该数组上运行。你可以做的最好的事情是给向量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]

而且,正如Praetorian所说,如果你使用的API希望你在使用后释放内存,你可能会对智能指针感兴趣。请参阅Praetorian's answer

答案 1 :(得分:10)

其他人建议你不能在一个向量中包装数组,但这根本不是真的;想一想,矢量有一个数组作为它的底层数据容器!在我想出一个可行的解决方案之前,我已经尝试了很长时间。需要注意的是,您必须在使用后将指针归零,以避免双重释放内存。

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

或者你可以创建一个继承自vector的类,并在销毁时将指针归零:

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

答案 2 :(得分:5)

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

这会将values中的数据复制到std::vector

答案 3 :(得分:5)

其他答案显示如何制作返回数组的副本并创建vector,但假设API为数组分配内存并希望调用者删除它,您可能还需要考虑坚持数组到智能指针并按原样使用。

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

您仍然可以将其复制到vector,但如果您执行上述步骤,则无需担心删除返回的数组。

答案 4 :(得分:1)

使用向量迭代器构造函数

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

答案 5 :(得分:0)

感谢@Ethereal提供了一个不错的解决方案,并使他/她的答案更加完整:

由于std实现方面的差异,该代码无法在Visual c ++中进行编译(也许会在GCC中进行编译),但进行一些更改后,它将可以完美地工作。

此代码已在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中,即使该指针是在堆中分配的(例如,使用new关键字) 因为std :: vector试图删除其析构函数中的指针,并且如果在堆栈上分配了数组指针,将导致两次删除相同的内存地址,并且将导致运行时错误。

因此您必须不要像这样包装堆栈分配的数组指针

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

答案 6 :(得分:0)

如果使用 C++11,您可以使用 std::vector<std::reference_wrapper<double>>

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

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

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 = 41.;
for(double& i: v) i = ++j;
    
std::cout << "Contents of the array: ";
for(auto i=0; i < N; ++i) std::cout << values[i] << ' ';
std::cout << '\n';

可能的输出:

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

亲:零拷贝

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