C ++ 11-2个向量之间的emplace_back不起作用 [英] C++11 - emplace_back between 2 vectors doesn't work

查看:156
本文介绍了C ++ 11-2个向量之间的emplace_back不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试修改一些代码,并使用emplace_back()

I was trying to adapt some code and moving the content from a vector to another one using emplace_back()

#include <iostream>
#include <vector>

struct obj
{
  std::string name;

  obj():name("NO_NAME"){}
  obj(const std::string& _name):name(_name){}

  obj(obj&& tmp): name(std::move(tmp.name)) {}
  obj& operator=(obj&& tmp) = default;

};

int main(int argc, char* argv[])
{

  std::vector<obj> v;
  for( int i = 0; i < 1000; ++i )
  {
    v.emplace_back(obj("Jon"));
  }

  std::vector<obj> p;
  for( int i = 0; i < 1000; ++i )
  {
    p.emplace_back(v[i]);
  }

  return(0);
}

此代码无法与g ++-4.7,g ++-4.6和clang ++一起编译:这有什么问题?

This code doesn't compile with g++-4.7, g++-4.6 and clang++: what it's wrong with it ?

我总是遇到1个关于

调用obj的隐式删除副本构造函数

call to implicitly-deleted copy constructor of obj

?

推荐答案

尽管现有答案提供了使用std::move的变通方法,可以使程序编译,但是必须说,您对emplace_back的使用似乎基于误会.

Although the existing answer provides a workaround using std::move that makes your program compile, it must be said that your use of emplace_back seems to be based on a misunderstanding.

您描述它的方式(我正在尝试使用emplace_back()将内容从矢量移动到另一个矢量" ),并且使用它的方式建议您将emplace_back视为将元素移动到向量中的方法,将push_back视为将元素复制到向量中的方法.用于填充向量的第一个实例的代码似乎也暗示了这一点:

The way you describe it ("I was trying to [...] moving the content from a vector to another one using emplace_back()") and the way you use it suggest that you think of emplace_back as a method to move elements into the vector, and of push_back as a method to copy elements into a vector. The code you use to fill the first instance of the vector seems to suggest this as well:

std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
  v.emplace_back(obj("Jon"));
}

但这不是emplace_backpush_back之间的区别.

But this is not what the difference between emplace_back and push_back is about.

首先,如果只赋予右值并且元素类型发生移动,即使push_back也会移动(不复制)元素到向量中赋值运算符.

Firstly, even push_back will move (not copy) the elements into the vector if only it is given an rvalue, and if the element type has a move assignment operator.

第二,emplace_back的真正用例是在原位置构造 元素,即,当您要将对象放入不包含矢量的矢量中时,可以使用它存在. emplace_back的参数是该对象的构造函数的参数.因此,您上面的循环应该看起来像这样:

Secondly, the real use case of emplace_back is to construct elements in place, i.e. you use it when you want to put objects into a vector that do not exist yet. The arguments of emplace_back are the arguments to the constructor of the object. So your loop above should really look like this:

std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
  v.emplace_back("Jon");   // <-- just pass the string "Jon" , not obj("Jon")
}

现有代码起作用的原因是obj("Jon")也是构造函数(特别是move构造函数)的有效参数.但是emplace_back的主要思想是无需创建对象然后将其移入.当您将obj("Jon")而不是"Jon"传递给它时,您不会从中受益

The reason why your existing code works is that obj("Jon") is also a valid argument to the constructor (specifically, to the move constructor). But the main idea of emplace_back is that you need not create the object and then move it in. You don't benefit from that idea when you pass obj("Jon") instead of "Jon" to it.

另一方面,在第二个循环中,您正在处理之前创建的对象.使用emplace_back移动已经存在的对象没有任何意义.同样,将emplace_back应用于现有对象并不意味着该对象已移动.它仅意味着使用普通的复制构造函数(如果存在)就地创建它.如果要移动它,只需使用应用于std::move结果的push_back:

On the other hand, in your second loop you are dealing with objects that were created before. There is no point in using emplace_back to move objects that exist already. And again, emplace_back applied to an existing object does not mean that the object is moved. It only means that it is created in-place, using the ordinary copy constructor (if that exists). If you want to move it, simply use push_back, applied to the result of std::move:

std::vector<obj> p;
for( int i = 0; i < 1000; ++i )
{
  p.push_back(std::move(v[i]));  // <-- Use push_back to move existing elements
}

更多笔记
1)您可以使用基于C ++ 11范围的以下代码来简化上述循环:

Further notes
1) You can simplify the loop above using C++11 range-based for:

std::vector<obj> p;
for (auto &&obj : v)
  p.push_back(std::move(obj));

2)不管您使用普通的for循环还是基于范围的for,都将元素一一移动,这意味着源向量v将作为1000个空对象的向量保留.如果您实际上想在过程中清除向量(但仍使用move语义将元素传输到新向量),则可以使用向量本身的move构造函数:

2) Regardless of whether you use an ordinary for-loop or range-based for, you move the elements one by one, which means that the source vector v will remain as a vector of 1000 empty objects. If you actually want to clear the vector in the process (but still use move semantics to transport the elements to the new vector), you can use the move constructor of the vector itself:

std::vector<obj> p(std::move(v));

这将第二个循环减少到仅一行,并确保清除了源向量.

This reduces the second loop to just a single line, and it makes sure the source vector is cleared.

这篇关于C ++ 11-2个向量之间的emplace_back不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆