移动构造函数和右值引用

时间:2018-10-10 14:17:58

标签: c++ constructor move-semantics

class Foo {
    int m_num;
public:
    Foo() {}

    Foo(int& n) {m_num = n;}

    Foo(int&& n) {m_num = n;}

    Foo(const Foo& src) {m_num = src.m_num;}

    Foo(Foo&& src) {m_num = src.m_num;}

    Foo& operator =(const Foo& src) {
        m_num = src.m_num;
        return *this;
    }

    Foo& operator =(Foo&& src) {// move
        m_num = src.m_num;
        return *this;
    }

    int& operator =(const int& src) {return m_num = src;}

    int& operator =(int&& src) {return m_num = src;}
};

为什么当我调用Foo f4(Foo(2));时调用Foo(int&& n)构造函数而不是Foo(Foo&& src)构造函数? 另外,为什么不传递作为右值引用的num调用move构造函数? 例如,Foo f = num不会调用move构造函数。

int main() {
    int&& num = 5;
    /*int num{ 5 };*/ // initializer-list
    Foo f = num; // custom constructor
    f = num; // assignment operator
    Foo f2 = 6; // custom move constructor
    f2 = 10; // custom move assignment
    f2 = f; // assignment operator
    Foo f3(f); // custom constructor
    // f3(f2); // ERROR
    f3 = (f2); // assignment operator

    Foo f4(Foo(2));

1 个答案:

答案 0 :(得分:2)

Foo(2)中,整数是一个右值,并且需要int&&中的右值引用构造函数。

如果是

 Foo f = num; // custom constructor 

不调用右值构造函数,因为命名值永远不会被视为右值。您必须致电std::move(num)才能使其正常工作。

标准以此方式定义它,以避免在命名值意外移动并随后使用时造成混淆的情况。即使该变量是右值引用,您也必须明确说明其移动方式。

编辑

根据cppreference,c ++ 17编译器必须忽略的copy / move构造函数(即在这种情况下,它不得调用或要求存在copy / move构造函数,这就是为什么您只能看到int&&的构造函数):

Foo f4(Foo(2));

这里是cppreference的引号(不如标准引号,但足够接近):

  

语言规则确保不进行任何复制/移动操作,   甚至在概念上:

     
      
  • 在初始化变量时,使用初始化表达式   是与类别相同(忽略cv限定)的类值   变量类型:

         

    T x = T(T(T())); //只需调用一次T的默认构造函数即可初始化x

  •