拷贝构造函数和移动构造函数的区别

拷贝构造函数和移动构造函数对于指针的处理是不一样的

  • 拷贝构造函数所做的是深拷贝,就是a拷贝到b中,需要在b中首先开辟一片空间在将a中的内容复制过去
  • 移动构造函数干的是浅拷贝,就是将a中的指针直接复制到b中,同时要将a中的指针指向的位置改变。

具体如下:

#include<iostream>

using namespace std;

class A_class
{
public :
   int * data_pointer;
   int n;
   A_class (int n){
       // data_pointer = (int *)malloc(n * sizeof(int));
       this->n = n;
       data_pointer = new int [n];
       for(int i = 0;i<n;i++){
           data_pointer[i] = i;
       }
   }
   ~ A_class (){       //  析构函数,free 和malloc相对应,new和delete相对应
       // free(data_pointer);
       delete(data_pointer);
       cout<<"finish"<<endl;
   }
   A_class(A_class && a):data_pointer(a.data_pointer),n(a.n){      // 移动构造函数,指针直接复制,
       // data_pointer = a.data_pointer;
       a.data_pointer = NULL;      // 被当作右值的对象,内部指针要被修改,所以形参中不能带有const
       //如果没有上面那句话,那么对于析构函数中的delete来说可能要对同一片地址free两次,这样在运行中就会产生错误!
       a.n = 0;
       cout<<"use right move"<<endl;
   }
   A_class (const A_class & a):n(a.n){       // 拷贝构造函数,由于拷贝的对象不能被修改,所以加上const
       this->data_pointer = new int[n];
       for(int i=0;i<a.n;i++){
           this->data_pointer[i] = a.data_pointer[i];
       }
   }
};
int main()
{
   A_class aa(10);
   A_class bb(move(aa));       //虽然强制转换aa为右值,但是并没有让aa直接被析构
   cout<<1<<endl;
   printf("%x\n",aa.data_pointer);
   printf("%x\n",bb.data_pointer);
   return 0;
}
// output 如下
/*
use right move
1
0
7c486eb0
finish
finish
*/

其中的std::move是将左值转化为右值的函数,使用过后aa就不能使用了(但是实际上在程序中好像还可以用,但是因为move将其转换为右值了,我们默认这个值之后不会使用了,所以将其中的指针指向的地址给了别的变量,aa就像当与一个要死的人,我们在把它的器官(所占内存空间)拿出来给别的变量,这个时候我们使用aa这个值就不行了,因为他的内存被我们给别人了,他对内存的控制就没了(表现在代码上就是他指向的位置已经不是他原来的空间了),所以使用aa就可能会出现错误),但是aa还是和一个变量一样你用还是能用,只不过资源被掠夺了,最终也会调用析构函数(所以注意别忘了在转移aa的内存空间的时候,别忘了给aa中指针一个新的地址,否则析构函数会将原来的内存地址释放两次)。

转发知乎上的回答:

太长不看:用于选择右值版本的重载函数
1.move函数除了把左值强制转为右值之外还有别的作用吗?没有了,不要看它叫move,实际上干的活就只有这点。
2.有人说在move(a)之后就不应该再使用a这个变量了,这是为什么?
你都已经强制转化右值了,说明接下来你肯定要使用右值。一般来说使用右值的目的就是将对象移动走,移动后以后只会剩下一具待析构的尸体,一般来说你是不会想使用它的。当然你可以std::move(a)但是不使用右值做移动操作,但是这样就没有使用std::move的意义了。
3.“使用”是指什么,赋值?访问a的值?当你移动对象以后,原来的对象变成一具尸体。语言保证这个尸体可以正常析构。因此,你可以对其重新赋值。一般不要访问a的值,即使你知道那个值不会被移动走。你举的例子中,像int这样的基本类型,std::move对其没有什么影响。因为它就不存在所谓移动操作。单独一个std::move的强制转换为右值只在语法上有意义,汇编中一条代码都不会生成的。

作者:Betty
链接:https://www.zhihu.com/question/467449795/answer/1960471015
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考:
C++引用和右值引用 - 知乎
https://www.zhihu.com/zvideo/1329558123930525696
C++右值引用(std::move) - niediao的文章 - 知乎
https://zhuanlan.zhihu.com/p/94588204
c++ 为什么右值引用,移动构造函数能避免不必要的拷贝? - 石鹏的回答 - 知乎
https://www.zhihu.com/question/512867700/answer/2321171432

C++11右值引用和移动构造函数详解 - 鹅厂程序小哥的文章 - 知乎
https://zhuanlan.zhihu.com/p/365412262

C++中的std::move函数到底是做什么的? - SynchronizX的回答 - 知乎
https://www.zhihu.com/question/467449795/answer/1961099671

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值