C++ C++;11-在两个向量之间放置回';行不通

C++ C++;11-在两个向量之间放置回';行不通,c++,vector,c++11,move-semantics,C++,Vector,C++11,Move Semantics,我试图修改一些代码,并使用emplace\u back() #包括 #包括 结构对象 { std::字符串名; obj():name(“NO_name”){} obj(const std::string&_name):name(_name){} obj(obj&&tmp):名称(std::move(tmp.name)){} obj和操作员=(obj和tmp)=默认值; }; int main(int argc,char*argv[]) { std::向量v; 对于(int i=0;i

我试图修改一些代码,并使用
emplace\u back()

#包括
#包括
结构对象
{
std::字符串名;
obj():name(“NO_name”){}
obj(const std::string&_name):name(_name){}
obj(obj&&tmp):名称(std::move(tmp.name)){}
obj和操作员=(obj和tmp)=默认值;
};
int main(int argc,char*argv[])
{
std::向量v;
对于(int i=0;i<1000;++i)
{
v、 后置炮台(obj(“Jon”));
}
std::向量p;
对于(int i=0;i<1000;++i)
{
p、 安置(v[i]);
}
返回(0);
}
这段代码不是用g++-4.7、g++-4.6和clang++编译的:它有什么问题

我总是有一个主要的错误

调用隐式删除的obj复制构造函数

问题是

p.emplace_back(v[i]);
将左值传递给
emplace\u back
,这意味着您的移动构造函数(需要右值引用)将无法工作

如果确实要将值从一个容器移动到另一个容器,则应显式调用:

(像
obj(obj&&tmp)这样的移动构造函数背后的思想)
是指
tmp
应该是一个不会存在太久的对象。在第一个循环中,您将一个临时对象传递给
emplace\u back
,这很好——右值引用可以绑定到临时对象并从中窃取数据,因为临时对象即将消失。在trong>second循环,你传递给
emplace\u back
的对象有一个名称:
v[i]
。这意味着它不是临时的,可以在程序中稍后引用。这就是为什么你必须使用它来告诉编译器“是的,我真的想从这个对象中窃取数据,即使其他人以后可能会尝试使用它。”)



Edit:我假设你对
emplace\u back
的非同寻常的用法是你不得不为我们制作一个小例子的遗物。如果情况并非如此,请参阅@jogojapan的答案,了解为什么使用
std::vector
move构造函数或重复调用
push_back
对您的示例更有意义。

尽管现有答案提供了一种使用
std::move
的解决方法,使您的程序能够编译,必须指出的是,您使用
emplace\u back
似乎是基于误解

您描述它的方式(“我试图[…]使用
emplace\u back()
”)将内容从一个向量移动到另一个向量)以及您使用它的方式表明,您认为
emplace\u back
是将元素移动到向量中的一种方法,而
push\u back
是将元素复制到向量中的一种方法。用于填充向量第一个实例的代码似乎也表明了这一点:

std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
  v.emplace_back(obj("Jon"));
}
现有代码工作的原因是,
obj(“Jon”)
也是构造函数(特别是移动构造函数)的有效参数。但是,
emplace\u back
的主要思想是,您不需要创建对象,然后将其移入。当你将
对象(“Jon”)而不是
Jon
传递给它时,你不会从这个想法中受益

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

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
}

这将第二个循环减少为一行,并确保源向量被清除。

错误消息告诉您,
obj
需要一个复制构造函数。@mat为什么需要构造?它不应该使用移动构造函数+移动赋值操作符?请检查的定义,您需要一个构造函数,该构造函数将您传递的
emplace\u返回
。您正在传递一个l值,但没有匹配的构造函数。@Mat我知道,但我的重点是v[i]表示什么,在此之前,我认为它是一个右值,因为它是对包含类型的地址的引用。
v[i]
是一个l值,可以分配给它。我确信v[i]是一个右值,因为它是对定义良好类型的位置的引用,所以奇怪的是它是一个左值。但是你的解决方案是有效的…@user1849534:我已经更新了答案,试图解释得更清楚一些。它的要点是,
v[i]
是一个左值,因为它是一个命名对象,您可以稍后参考。谢谢!一个非常好的解释,我还有一件事要解释,那就是陈述for
循环中的code>之所以有效,是因为作用域解析机制选择了正确的(在我的例子中是错误的)构造函数?哦,它之所以有效,是因为
obj(“Jon”)
是一个右值(因为它是一个临时对象)。因此,
emplace\u back
调用接受右值引用的构造函数,
obj::obj(obj&&tmp)
。如果您首先将对象存储在变量(即左值)中,如下所示:
obj x=obj(“Jon”)然后调用
emplace_back(x)
那么它就不会工作,因为
x
不是右值。相反,它会搜索构造函数
obj(obj&tmp)
obj(const obj&tmp)
,但它不会找到任何构造函数,因此我认为它会失败。
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
  v.emplace_back(obj("Jon"));
}
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
  v.emplace_back("Jon");   // <-- just pass the string "Jon" , not obj("Jon")
}
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
}
std::vector<obj> p;
for (auto &&obj : v)
  p.push_back(std::move(obj));
std::vector<obj> p(std::move(v));