当我需要从另一个容器的一些元素(假设是另一个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的循环(我夸大了这一点),并导致许多容器内存重新分配在其创建过程中作为副本?
是由标准保证的,或者至少我可以依赖现有的实现,它们不会多次重新分配内存?
我之所以担心,是因为我使用的是巨大的容器,并希望确保这种可读性更强的代码不会对性能产生影响。
2条答案
按热度按时间axkjgtzd1#
我在C++23标准中找到了这段话:
24.3.11.2构造函数[vector.cons]
字符串
1.效果:使用指定的分配器构造一个等于范围
[first, last)
的vector
。1.复杂性:只对T的复制构造函数进行N次调用(其中N是第一个和最后一个之间的距离),如果第一个和最后一个迭代器属于正向、双向或随机访问类别,则不进行重新分配。它对T的复制构造函数进行N次调用,如果它们只是输入迭代器,则进行log N次重新分配。
这意味着一个符合规范的实现将至少与您手动调用
reserve
+insert
一样有效。lskq00tm2#
根据https://en.cppreference.com/w/cpp/container/vector/vector#Complexity,第五个列出的构造函数(对于两个迭代器),对于非输入迭代器,不会发生重新分配。构造函数必须执行与
reserve(distance(first, last))
等效的操作才能符合标准。因此,您的
std::vector<int> v2(v1.begin(), v1.begin() + amount);
将只有一个分配。