2016-07-16 92 views
1
class MyClass { 
    public: 
     MyClass() 
     { 
      std::cout << "default constructor\n"; 
     } 
     MyClass(MyClass& a) 
     { 
      std::cout << "copy constructor\n"; 
     } 

     MyClass(MyClass&& b) 
     { 
      std::cout << "move constructor\n"; 
     } 
}; 

void test(MyClass&& temp) 
{ 
    MyClass a(MyClass{}); // calls MOVE constructor as expected 
    MyClass b(temp); // calls COPY constructor... not expected...? 
} 

int main() 
{ 
    test(MyClass{}); 
    return 0; 
} 

对于上面的代码中,我预期无论在测试对象创建()来调用移动的构造,因为b是右值引用类型(MyClass的& &)。c + +移动的构造不要求右值参考

但是,将b传递给MyClasss构造函数并不像预期的那样调用移动构造函数,而是调用复制构造函数。

为什么第二个案例调用拷贝构造函数,即使传入的参数是MyClass类型& &(r值参考)???

我使用的是gcc 5.2.1。要重现我的结果,您必须将-fno-elide-constructors选项传递给gcc以禁用副本优化。


void test(MyClass&& temp) 
{ 
    if (std::is_rvalue_reference<decltype(temp)>::value) 
     std::cout << "temp is rvalue reference!!\n"; 
    else 
     std::cout << "temp is NOT rvalue!!\n"; 
} 

上面的代码打印出“温度是右值引用”,即使温度而得名。

temp的类型是右值引用类型。

+0

表达'temp'计算结果为左值refernce,而不是右值引用。你将'temp'声明为右值引用并不重要。一个*名为*的引用永远是一个左值。 – AnT

+0

@AnT你在C++标准文档中有任何参考吗?我非常努力地寻找这条规则的任何参考,但我找不到一个...... – SHH

+2

请参阅** 5表达式**的开头。全部在5/5,5/6和5/7。特别参见注5/7,它基本上是这样描述的。此外,链接的“重复”链接到一个托马斯贝克尔关于这个话题的文章。 – AnT

回答

3
void test(MyClass&& temp) 
{ 
    MyClass a(MyClass{}); // calls MOVE constructor as expected 
    MyClass b(temp); // calls COPY constructor... not expected...? 
} 

这是因为,temp(因为它有一个名字,)是lvalue参照一个rvalue。为了治疗为rvalue在任何时候,呼吁std::move

void test(MyClass&& temp) 
{ 
    MyClass a(MyClass{}); // calls MOVE constructor as expected 
    MyClass b(std::move(temp)); // calls MOVE constructor... :-) 
} 
+0

'一个左值的左值引用'...右值如何具有左值引用?这超出了我的理解。 – Youda008