2017-11-11 266 views
3

给定一个原始数组元素,如何创建一个std::vector,该数组获取原始数组的所有权而不用重新分配& copy?从原始数据创建std :: vector

例如具有原始阵列:

int* elems = new int[33]

如何创建尺寸33指向elemsstd::vector

我相信理论上这是可能的,因为通常std::vector被实现为包含三个指针的结构,一个指向分配内存的开始,一个指向有效元素的末尾,一个指向有效元素的末尾,一个指向末尾分配的内存。但有没有一种标准的方式来初始化原始数组的std::vector结构?

+5

你不能。不要使用新的“原始数据”,使用矢量。 – 2017-11-11 09:04:48

+2

如果你需要像'begin'或'front'这样的常用方法,你可以在'unique_ptr '中存储指向数组的指针并通过'array_view '访问数组内容。 – VTT

+1

做相反的事情:让'vector'管理内存,并创建一个指向它的指针'std :: vector v; int * elems = v.data();' – Tas

回答

1

根据this,没有构造函数接受指向数据的指针。所以,你不能将原始数组的所有权传递给vector。

您只能创建一个向量并将数据放入其中。

+0

我知道根据引用的来源,没有办法做到这一点,但你不觉得这是可能的和有用的,这应该有可能做到这一点? – cDc

+1

@cDc矢量如何安全地获取指针的所有权?没有办法将它限制为动态分配的指针。 – user0042

+0

不确定你的意思;通过拥有所有权,我的意思是'elems'变量不会在'std :: vector'创建后被使用,并且数组的所有管理都将通过'std :: vector'方法完成,包括添加/删除元素。 – cDc

2

这不是直接可能的原因是标准库使用分配器为容器保留内存。

因此,如果你有一个std::vector它使用某种类型的分配器,并给它一些你创建的指针,你会有效地打破分配器的习惯用法。如果您的标准库的实现例如使用mallocfree而不是newdelete,则程序将失败。

对于这个成为标准方式,标准库需要提供接受其还必须已经由矢量后使用相同的分配器返回T*构造。所以你需要的构造函数的签名就像std::vector::vector(T* data, size_type used_elements, size_type capacity, const Allocator& alloc)。请注意,allocator参数是必需的,因为T*必须(理论上)由向量中使用的完全相同的分配器返回。


您可以通过创建根据this concept你自己的分配器实现 一些功能 这一点,但有你的33元素无法重建你还必须提供一个allocator::construct(..)功能是无糖op直到34th元素(不包括)。此外,您必须首先将矢量调整为33元素,以强制矢量具有正确的大小。

这是说这不过是一个坏主意,因为对于条件构造和分配函数,您可能会有更多的开销,而不是复制一次元素。

+0

的'的std :: VECTOR'声明是 '''模板< 类T, 类分配器=标准::分配器 >类矢量; ''' 所以创建的向量可以伴随正确的分配器,包括'malloc'和'free' – cDc

+1

@cDc是的,但不幸的是我不知道你想告诉我这个.. – nyronium

+0

@nyronium我认为你*可以*写一个合法的分配器来完成OP所需要的;分配器会检查T *和它的初始化大小是否与竞技场内存相匹配,并将分配和构造变成几乎没有操作(当然,分配器仍然会复制增长)... –

3

你需要的是一个“视图”而不是一个容器。容器拥有自己的元素,其主要目的是封装他们管理的原始记忆。如果你需要自己管理内存,那么你不需要容器。看看string_view这将是你的解决方案,如果你有一个string。也许boost ranges是你可以应用的东西。从文档(强调雷):

的范围概念的动机是,有一些可以与写了很多有用的集装箱般 类型不符合 集装箱的全部要求,很多算法这减少了 一组要求。特别是,范围并不一定

  • 拥有可以通过它访问的元素,
  • 有复制语义,

PS:其实std::array_view被认为是C + +17,但不幸的是它并没有成为标准。

+0

'std :: array_view'没有把它变成C++ 17。 –

+0

@ChristianHackl thx,已更新 – user463035818

0

鉴于原始的排列要素,如何创建一个std::vector是 需要原始阵列的所有权,而不再分配&副本?

有没有办法。

如何创建一个尺寸为33的std::vector指向elems?

不可能。

我相信,在理论上这是可能的,

不,事实并非如此。

但是有没有标准的方式初始化std::vector结构与原始数组?


话虽这么说号,有机会,你可能能够破解连同自定义分配器的解决方案。但是,除了编写自定义分配器是很少使用的容易出错的技术之外,您不应该高估此类解决方案的可用性。

std::vector<int>std::vector<int, MyAllocator>两个不同的类。如果您的目标是与预期为std::vector<int>的代码进行交互,则不能使用std::vector<int, MyAllocator>;如果您打算在您的代码中创建并使用std::vector<int, MyAllocator>,那么说实话,您最好是实施自己的非拥有容器类,即类似自定义VectorView<T>

0

如果你正在使用的对象的类型是可移动的,你可以这样做:

template<typename T> 
std::vector<std::unique_ptr<T>> ConvertArrayToVector(T* data, size_t size) 
{ 
    std::vector<std::unique_ptr<T>> result(size); 
    for (unsigned int i = 0; i<size; ++i) 
     result[i] = std::make_unique<T>(std::forward<T>(data[i])); 

    return result; 
} 

所产生的载体现已拥有阵列,因为它存储指向它的元素,并确保感当向量被销毁时对象被删除,但原始数组在过程中被取消。