c++11 move 不生效?

c++11 move not take effective?

我测试了c++11的move函数,没有生效。谁能告诉我为什么?谢谢。代码如下:

class Base {
  public:
   Base() { cout << "Base" << endl;}
   ~Base() { cout << "~Base" << endl;}

   Base(const Base& base) { cout << "Copy" << endl; }
   Base& operator=(const Base& base) {cout << "operator=" << endl;}

   Base(Base&& base) { cout << "move" << endl;}
   Base& operator=(Base&& base) { cout << "move=" << endl;}
};

Base b;

Base&& GetResult() {
  return std::move(b);
} 

int main() {
Base&& tmp = GetResult();

cout << &b << endl;
cout << &tmp << endl;

}

输出:

 Base
 0x6013a0
 0x6013a0
 ~Base

为什么 move copymove operator= 不被调用?为什么地址是一样的?

Why move copy and move operator= not be called ?

我假设 "move copy" 是指 "move constructor"。移动赋值运算符不被调用,因为你从不使用赋值运算符。

没有移动(也没有复制),因为 Base&& 是一个 引用 (具体来说是一个右值引用)。引用引用/指向一个对象——它们不包含对象的状态。初始化引用时,不会复制或移动任何对象。

And why address is the same ?

当 address-of 运算符应用于引用时,您将获得引用对象的地址。

让我们暂时忽略移动语义,只考虑熟悉的 C++98 复制构造函数。给定以下代码,您期望得到什么输出?

class Base {
  public:
   Base() { cout << "Base" << endl;}
   ~Base() { cout << "~Base" << endl;}

   Base(const Base& base) { cout << "Copy" << endl; }
   Base& operator=(const Base& base) {cout << "operator=" << endl;}
};

Base b;

Base& GetResult() {
  return b;
} 

int main() {
  Base& tmp = GetResult();

  cout << &b << endl;
  cout << &tmp << endl;
}

当然,您会期望调用 Base 默认构造函数,然后是打印两次的 b 地址,然后是 Base 析构函数。原因是因为您只构建了一个 Base 实例,并且从不复制它——您只是在使用引用。

你的例子也是如此。您使用的是右值引用而不是左值引用,但要点是相同的——只有一个 Base 变量,并且不会发生任何复制或移动。如果你想见证动作语义,你可以尝试这样的事情:

Base getBase() {
    return Base{};
}

int main() {
    Base tmp = getBase();
    Base other = std::move(tmp);
}

getBase() 的移出可能会被编译器优化掉,但你仍然应该看到第二个。)

为了补充现有的优秀答案,我认为这里的主要混淆点是 std::move 的作用。

std::move不动.

它的名字非常糟糕

它只会给你一个 xvalue,指的是你给它的任何东西;此 xvalue 将绑定到右值引用,而左值则不会。这意味着 std::move 的结果可以 提供给移动构造函数或移动赋值运算符。但是,它不会为您做这些,您也不会在这里做。


Given such strong criticism for the naming, surely you have an alternative suggestion
user2079303

这是一个老生常谈的话题,但是 the creator of C++ suggests std::rval, and one of the architects of modern C++ suggests std::rvalue_cast(即使你实际上得到了一个 xvalue)。

就我个人而言,我认为 std::moveable 会是一个很好的中间立场。