从原始数据就地创建std :: vector

时间:2017-11-11 09:02:08

标签: c++ arrays vector memory-management

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

例如,拥有原始数组:

int* elems = new int[33]

如何创建指向std::vector的{​​{1}}大小33

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

5 个答案:

答案 0 :(得分:3)

您需要的是“视图”而不是容器。容器拥有它们的元素,它们的主要目的是封装它们管理的原始内存。如果您需要自己管理内存,那么您不需要容器。如果您有string_view,请查看string这将是您的解决方案。或许boost ranges可以适用。来自文档(强调我的):

  

Range概念的动机是有很多有用的   容器类型不符合完整要求   容器和许多可以用这种方法编写的算法减少了   一套要求。特别是,Range不一定

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

PS:实际上std::array_view被认为是C ++ 17,但遗憾的是它没有成为标准。

答案 1 :(得分: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(..)函数,该函数在34th元素(不包括)之前是无操作的。此外,您必须首先将矢量调整为33个元素,以强制矢量具有正确的大小。

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

答案 2 :(得分:1)

根据this,没有构造函数接受指向数据的指针。因此,您无法将原始数组的所有权传递给矢量。

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

答案 3 :(得分: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>

答案 4 :(得分: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;
}

结果向量现在拥有数组,从某种意义上说,它存储指向其元素的指针,并确保在向量被销毁时删除对象,但原始数组在此过程中失效。