8

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

 3 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzU3ODk2NDYyNA%3D%3D&%3Bmid=2247483778&%3Bidx=1&%3Bsn=d81b6dfc336a219268cd64308ca1e57b
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

  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. }

aaQrmuu.png!mobile

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

#include <iostream>
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

nUn6J3.png!mobile

非常量的左值引用和右值不能绑定,这也就说明不加const不能接收右值。

值得注意的地方:右值短暂,左值持久。也就是右值引用只能绑定到临时对象,该对象在后续代码中没有任何作用。

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK