C++为什么提供move函数？
或者说，compiler为什么不能向程序员隐藏这个功能，由compiler自己选择什么情况下move？而什么情况下，需要程序员去指定move？
第一个问题的答案很简单，因为 **编译器真的不敢** 。

编译器在优化性能的同时，必须保证代码执行结果完全不变。

比方说你写了这样一段程序：

            class A {    public:        A& operator=(const A&);        A& operator=(A&&);    };        int main() {        A a, b;        a = b;    }    

你可能会说，执行 `a = b` 后程序就结束了，`b` 的资源不会再用到，所以这里应该进行移动赋值。

可是，万一你把赋值重载写成了这样呢？

            A& operator=(const A&) {        std::cout << "copy" << std::endl;        return *this;    }    A& operator=(A&&) {        std::cout << "move" << std::endl;        return *this;    }    

输出内容可就变了！明明代码让调用某个函数（拷贝赋值），却擅自改成调用另一个函数（移动赋值），编译器可不敢干这种事。

**以左值为参数时调用拷贝构造/赋值，以右值为参数时调用移动构造/赋值，这是天经地义的。编译器不会试图修改一个表达式的值类别（即从右值转换为左值或反之）。**

（某种意义上，这句话应该反过来说。以左值引用为参数的构造函数/赋值重载称为拷贝构造/赋值，以右值引用为参数的构造函数/赋值重载称为移动构造/赋值。）

所以，如果你想调用移动赋值，就必须用 `std::move` 告诉编译器“啊，虽然这是一个左值，但你一定要把它当右值看待”。

因此第二个问题的答案呼之欲出： **如果你想对一个左值启用移动语义，就必须用`std::move` 将其转换为右值引用。**

既然都铺垫到这里了，那我们最后再简单说说一个有意思的问题，如果 `std::move` 是用来把左值转换成右值的，那什么是把右值转换成左值的呢？

答案是：右值引用！ **右值引用是左值！**

来看这样一段代码：

            class A {    public:        void foo(A&& other) {            val(other);        }    	        void val(A&) {            std::cout << "1" << std::endl;        }        void val(A&&) {            std::cout << "2" << std::endl;        }    };        int main() {        A a, b;        a.foo(std::move(b));    }    

你猜调用的是 `void val(A&)` 还是 `void val(A&&)`？可能很多人会信誓旦旦地说：在 `foo` 里面 `other` 是`A&&` 类型，那当然调用的是 `void val(A&&)` 了。

很可惜，事实上，这里调用的是 `void val(A&)`，不信的话可以自己试试。

再说一次， **右值引用是左值** ，所以当然会调用左值引用的版本。

但是，右值引用他凭什么是左值呢？他明明是右值的引用啊。

如果细细考虑的话，这其实是合理的。

当我们定义一个右值引用的时候，我们会给出变量名（例如 `other`），而这个名字在作用域内是可以多次使用的，我们大可以写出这样的代码：

                void foo(A&& other) {            other = A();            A* p = &other;        }    

多次使用、出现在赋值号左侧、可以取地址，这可都是左值的性质。

最后总结一下：

1. 编译器不会试图修改表达式的值类别。

2. 以左值为实参时，调用以左值引用为形参的重载；以右值为实参时，调用以右值引用为形参的重载。

3. `std::move` 用于将左值转换为右值。

4. 右值引用是左值。