c++ 如何在从另一个容器创建std::vector时确保一次内存分配?

fnatzsnv  于 2023-11-19  发布在  其他
关注(0)|答案(2)|浏览(99)

当我需要从另一个容器的一些元素(假设是另一个vector)创建一个std::vector时,确保新vector只在内存中分配一次(技术上是两次,但我们忽略起始tine大小)的最安全方法是:

std::vector<int> v1 = { 1, 2, 3, 4, 5, 6 };
const size_t amount = 3;
std::vector<int> v2;
v2.reserve(amount);
v2.insert(v2.begin(), v1.begin(), v1.begin() + amount);

字符串
同时,这段代码比Best way to extract a subvector from a vector中非常简单的结构要长得多,

std::vector<int> v1 = { 1, 2, 3, 4, 5, 6 };
const size_t amount = 3;
std::vector<int> v2(v1.begin(), v1.begin() + amount);


std::vector<int> v1 = { 1, 2, 3, 4, 5, 6 };
const size_t amount = 3;
std::vector<int> v2 = {v1.begin(), v1.begin() + amount};


问题是,后一种情况是否确保v2的内存只分配一次,或者特定的实现可以很容易地使用类似push_back或emplace_back的循环(我夸大了这一点),并导致许多容器内存重新分配在其创建过程中作为副本?
是由标准保证的,或者至少我可以依赖现有的实现,它们不会多次重新分配内存?
我之所以担心,是因为我使用的是巨大的容器,并希望确保这种可读性更强的代码不会对性能产生影响。

axkjgtzd

axkjgtzd1#

我在C++23标准中找到了这段话:
24.3.11.2构造函数[vector.cons]

template<class InputIterator>
constexpr vector(InputIterator first, InputIterator last,
const Allocator& = Allocator());

字符串
1.效果:使用指定的分配器构造一个等于范围[first, last)vector
1.复杂性:只对T的复制构造函数进行N次调用(其中N是第一个和最后一个之间的距离),如果第一个和最后一个迭代器属于正向、双向或随机访问类别,则不进行重新分配。它对T的复制构造函数进行N次调用,如果它们只是输入迭代器,则进行log N次重新分配。
这意味着一个符合规范的实现将至少与您手动调用reserve + insert一样有效。

lskq00tm

lskq00tm2#

根据https://en.cppreference.com/w/cpp/container/vector/vector#Complexity,第五个列出的构造函数(对于两个迭代器),对于非输入迭代器,不会发生重新分配。构造函数必须执行与reserve(distance(first, last))等效的操作才能符合标准。
因此,您的std::vector<int> v2(v1.begin(), v1.begin() + amount);将只有一个分配。

相关问题