考虑以下程序,将一系列元素插入到矢量中:
vector<string> v1;
vector<string> v2;
v1.push_back("one");
v1.push_back("two");
v1.push_back("three");
v2.push_back("four");
v2.push_back("five");
v2.push_back("six");
v1.insert(v1.end(), v2.begin(), v2.end());
这有效地复制了范围,在整个范围内为目标矢量分配了足够的空间,因此最多需要一个调整大小。现在考虑以下程序尝试将范围移动到向量中:
vector<string> v1;
vector<string> v2;
v1.push_back("one");
v1.push_back("two");
v1.push_back("three");
v2.push_back("four");
v2.push_back("five");
v2.push_back("six");
for_each ( v2.begin(), v2.end(), [&v1]( string & s )
{
v1.emplace_back(std::move(s));
});
这会执行成功的移动但不会享受insert()在目标向量中预分配空间方面的优势,因此在操作期间可以多次调整向量的大小。
所以我的问题是,是否存在可以将范围移动到向量中的插入等效项?
答案 0 :(得分:78)
您使用move_iterator
与insert
:
v1.insert(v1.end(), make_move_iterator(v2.begin()), make_move_iterator(v2.end()));
24.5.3中的例子几乎就是这个。
如果(a)vector::insert
使用iterator-tag dispatch来检测随机访问迭代器并预先计算大小(您假设它在您的示例中复制了),您将获得所需的优化,和(b)move_iterator
保留它包装的迭代器的迭代器类别(这是标准所要求的)。
在一个模糊的观点上:我很确定vector::insert
可以从源(这在此处无关紧要),因为源与目的地的类型相同,因此一个emplace与副本相同/ move,但与其他相同的例子相关)。我还没有发现需要这样做的声明,我只是通过传递给i,j
的迭代器对insert
的要求是T
的事实推断出来的。来自EmplaceConstructible
的{{1}}。
答案 1 :(得分:33)
std::move
算法:
#include <iterator>
#include <algorithm>
v1.reserve(v1.size() + v2.size()); // optional
std::move(v2.begin(), v2.end(), std::back_inserter(v1));
以下内容会更加灵活:
v1.insert(v1.end(),
std::make_move_iterator(v2.begin()),
std::make_move_iterator(v2.end()));
Steve Jessop提供了有关它的确切内容的背景信息,以及它是如何做到的。