有没有将范围移动到矢量的标准方法?

Ben*_*enj 52 c++ insert stdvector c++11

考虑以下程序,它将一系列元素插入到向量中:

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());
Run Code Online (Sandbox Code Playgroud)

这有效地复制了范围,在整个范围内为目标矢量分配了足够的空间,因此最多需要一个调整大小.现在考虑以下程序尝试将范围移动到向量中:

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));
});
Run Code Online (Sandbox Code Playgroud)

这会执行成功的移动,但不会享受insert()在目标向量中预分配空间方面的优势,因此在操作期间可以多次调整向量的大小.

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

Ste*_*sop 81

您可以使用一个move_iterator具有insert:

v1.insert(v1.end(), make_move_iterator(v2.begin()), make_move_iterator(v2.end()));
Run Code Online (Sandbox Code Playgroud)

24.5.3中的例子几乎就是这个.

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

在一个不起眼的地方:我很确定它vector::insert可以从源头放置(这里不相关,因为源是与目的地相同的类型,因此一个空格与复制/移动相同,但是与之相关否则相同的例子).我还没有找到一个声明,它的要求这样做,我只是一个事实,即对迭代器对的要求推断它i,j传递到insert的是,TEmplaceConstructible*i.

  • 嗯,我发现也可以使用`make_move_iterator`将`std :: copy_if`变成`std :: move_if`的等价物.这非常方便. (4认同)
  • 太好了,不知道`make_move_iterator` (3认同)

seh*_*ehe 33

  1. std::move 预分配算法:

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

    v1.insert(v1.end(), 
         std::make_move_iterator(v2.begin()), 
         std::make_move_iterator(v2.end()));
    
    Run Code Online (Sandbox Code Playgroud)

    Steve Jessop提供了有关它的确切内容的背景信息,以及它是如何做到的.

  • 我认为第一个实际上只能重新分配一次:`move`可以看到你有一个随机访问迭代器,所以它可以计算出所需的大小,但它只能看到一个`back_insert_iterator`,而不是底层的向量,所以它没有办法预留空间.它需要一个令人难以置信的曲折的'std :: move`重载来捕捉这种情况. (4认同)
  • 哦,整洁,不知道这种形式的`std :: move`.虽然我猜`back_inserter`仍然会导致多次调整大小. (2认同)