给定一个原始元素数组,如何创建一个std::vector
来获取原始数组的所有权而不重新分配&副本?
例如,拥有原始数组:
int* elems = new int[33]
如何创建指向std::vector
的{{1}}大小33
?
我确信理论上这是可能的,因为通常elems
被实现为包含三个指针的结构,一个指向已分配内存的开头,一个指向有效元素的末尾,一个指向已分配内存的结束。但是有没有一种标准方法用原始数组初始化std::vector
结构?
答案 0 :(得分:3)
您需要的是“视图”而不是容器。容器拥有它们的元素,它们的主要目的是封装它们管理的原始内存。如果您需要自己管理内存,那么您不需要容器。如果您有string_view
,请查看string
这将是您的解决方案。或许boost ranges可以适用。来自文档(强调我的):
Range概念的动机是有很多有用的 容器类型不符合完整要求 容器和许多可以用这种方法编写的算法减少了 一套要求。特别是,Range不一定
- 拥有可以通过它访问的元素,
- 有复制语义,
PS:实际上std::array_view
被认为是C ++ 17,但遗憾的是它没有成为标准。
答案 1 :(得分:2)
这不能直接实现的原因是标准库使用分配器来为容器保留内存。
因此,如果你有std::vector
使用某种类型的分配器并给它一些你创建的指针,你就会有效地破坏分配器的习语。如果您的标准库实现使用malloc
和free
而不是new
和delete
,则您的程序将失败。
为了使其成为标准方式,标准库需要提供一个接受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;
}
结果向量现在拥有数组,从某种意义上说,它存储指向其元素的指针,并确保在向量被销毁时删除对象,但原始数组在此过程中失效。