64

考虑以下将一系列元素插入向量的程序:

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() 在目标向量中预分配空间方面的好处,因此在操作期间可以多次调整向量的大小。

所以我的问题是,是否有插入等效项可以将范围移动到向量中?

4

2 回答 2

99

您使用move_iteratorwith insert

v1.insert(v1.end(), make_move_iterator(v2.begin()), make_move_iterator(v2.end()));

24.5.3 中的例子几乎就是这样。

vector::insert如果 (a)使用 iterator-tag dispatch 来检测随机访问迭代器并预先计算大小(您假设它在您的示例中复制),并且 (b)move_iterator保留迭代器,您将获得所需的优化它包装的迭代器的类别(标准要求)。

在一个模糊的点上:我很确定vector::insert可以从源放置(这在这里无关紧要,因为源与目标的类型相同,所以放置与复制/移动相同,但与其他相同的例子)。我还没有找到必须这样做的声明,我只是从i,j传递给的迭代器对的要求insert是from的事实T推断出来的。EmplaceConstructible*i

于 2012-05-23T12:48:20.167 回答
41
  1. std::move预分配算法:

    #include <iterator>
    #include <algorithm>
    
    v1.reserve(v1.size() + v2.size()); // optional
    std::move(v2.begin(), v2.end(), std::back_inserter(v1));
    
  2. 以下将更加灵活:

    v1.insert(v1.end(), 
         std::make_move_iterator(v2.begin()), 
         std::make_move_iterator(v2.end()));
    

    Steve Jessop 提供了关于它具体做什么以及它可能是如何做的背景信息。

于 2012-05-23T12:45:55.830 回答