C++11为什么引入移动构造函数和右值引用?

这个问题很多人都知道,移动构造函数可以不像拷贝构造函数那样深层拷贝。

  1. class
    Student {

  2. private
    :

  3. int
    *
    numID ;

  4. public
    :

  5. Student():
    numID
    (
    new
    int
    (
    0
    ))
    {

  6. cout <<
    “construct!”
    <<
    endl ;

  7. }
  8. //深层拷贝构造函数
  9. Student(
    const
    Student &
    d ):
    numID
    (
    new
    int
    (*
    d .
    numID ))
    {

  10. cout <<
    “copy construct!”
    <<
    endl ;

  11. }
  12. //添加移动构造函数
  13. Student(Student
    &&
    d ):
    numID
    (
    d .
    numID )
    {

  14. d .
    numID =
    nullptr ;

  15. cout <<
    “move construct!”
    <<
    endl ;

  16. }
  17. ~Student
    ()
    {

  18. cout <<
    “class destruct!”
    <<
    endl ;

  19. }
  20. }
    ;

上面一个Student类, 实现了一个拷贝构造函数(深层拷贝)和移动构造函数。我们发现移动构造函数其实执行的浅层拷贝,只不过多了将numID置空的操作,那么现在真正的问题来了,那我直接写一个浅层的拷贝构造函数, 再加一个numID置空的操作不就可以了吗?

  1. //错误的浅层拷贝
  2. Student(const Student
    &
    d ):
    numID
    (
    d .
    num )
    {

  3. d .
    numID =
    nullptr ;//此句不能编译通过

  4. cout <<
    “move construct!”
    <<
    endl ;

  5. }


理想很丰满,现实是这是错误的。d 由const 修饰,那么numID 是不能修改的。到这里有人想到,那去掉const 不就可以了吗?wow, 确实,我也是这么想的。也就是说可以如下写:

#include 
using namespace std;
class Student{
private:
int *numID;
public:
Student():numID(new int(0)){
cout<<"construct!"<<endl;
}
//深层拷贝构造函数
Student(const Student &d):numID(new int(*d.numID)){
cout<<"copy construct!"<<endl;
}
//添加移动构造函数
Student(Student &&d):numID(d.numID){
d.numID =nullptr;
cout<<"move construct!"<<endl;
}
//
Student(Student &d):numID(d.numID){
d.numID =nullptr;
cout<<"false copy construct!"<<endl;
}
~Student(){
cout<<"class destruct!"<<endl;
}
};


int main()
{
const Student s;//
Student ss(s);
return 0;
}

这样确实可以解决指针悬挂问题,也类似移动构造函数,那为什么C++11要大费周章的引入移动构造和右值引用??
看如下代码:

Student(int &d){
numID = &d;
}
//main
Student(10);//error


非常量的左值引用和右值不能绑定,这也就说明不加const不能接收右值。
值得注意的地方:右值短暂,左值持久。也就是右值引用只能绑定到临时对象,该对象在后续代码中没有任何作用。
结合起来也就明白为什么要引入右值引用&&这个新类型和移动构造函数,移动构造是为右值而生的,也就是为临时对象而生的(当然左值可以通过std::move()转换右值,避免深层拷贝)。临时对象是在后续代码中没有用的,因此可以将指针置空。而自己写的去掉const 的“拷贝构造”是不能接收右值的,这样就很没意义。