用汇编的眼光看C++(之算术符重载陷阱)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/feixiaoxing/article/details/6831639

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】


    在算术符重载里面,“=”重载可能是最经常使用的一种。但是好多人就误以为在函数中,凡是类出现“=”的地方,那就是调用算术符重载,其实不然。为什么呢?我们可以看看下面的代码。首先,我们定义一个基本类:


 
 
  1. class data
  2. {
  3. char* value;
  4. int number;
  5. public:
  6. explicit data(int num = 0){
  7. if(num){
  8. number = num;
  9. value = ( char*)malloc(num);
  10. }
  11. }
  12. data( const data& d){
  13. number = d.get_number();
  14. value = ( char*)malloc(d.get_number());
  15. memmove( value, d.get_point(), d.get_number());
  16. }
  17. ~data(){
  18. if(number)
  19. free( value);
  20. }
  21. data& operator=( const data& d){
  22. if(number)
  23. free( value);
  24. number = d.get_number();
  25. value = ( char*)malloc(d.get_number());
  26. memmove( value, d.get_point(), d.get_number());
  27. return * this;
  28. }
  29. int get_number() const { return number;}
  30. char* get_point() const { return value;}
  31. };

    定义好了函数之后,我们就开始对这个类进行调用,同样代码如下所示:


 
 
  1. 45: data m(10);
  2. 0040108D push 0Ah
  3. 0040108F lea ecx,[ebp-14h]
  4. 00401092 call @ILT+ 30( data:: data) ( 00401023)
  5. 00401097 mov dword ptr [ebp -4], 0
  6. 46: data p = m;
  7. 0040109E lea eax,[ebp-14h]
  8. 004010A1 push eax
  9. 004010A2 lea ecx,[ebp-1Ch]
  10. 004010A5 call @ILT+ 35( data:: data) ( 00401028)
  11. 004010AA mov byte ptr [ebp -4], 1
  12. 47: p = m;
  13. 004010AE lea ecx,[ebp-14h]
  14. 004010B1 push ecx
  15. 004010B2 lea ecx,[ebp-1Ch]
  16. 004010B5 call @ILT+ 5( data:: operator=) ( 0040100a)
  17. 48: }
    上面共有三句话,我们逐一进行分析:

    45句:定义了一个临时变量,调用data的构造函数

    46句:出现了一个临时变量p,这里发现data类并没有调用算术符重载函数,而是调用了data的构造函数,根据45句所示,调用的肯定不是普通的构造函数,那么剩下的结果只能是拷贝构造函数

    47句: 和46句的代码是一致的,但是此时调用的函数才是算术符重载函数

    所以说,出现“=”的地方未必调用的都是算术符重载函数,也有可能是拷贝构造函数。那么什么时候是拷贝构造函数,什么时候是算术符重载函数呢?判断的标准其实很简单。如果临时变量是第一次出现,那么调用的只能是拷贝构造函数,反之如果变量已经存在,就像47句一样,那么调用的只能是算术符重载函数,但是我们这里定义的算数符重载函数有一个陷阱,不知道大家看出来没有?

    我提示大家一下,这里的算术符重载需不需要判断拷贝的是不是自己呢?


 
 
  1. void process()
  2. {
  3. data m(10);
  4. data p = m;
  5. p = p;
  6. }
    这里最后一句,如果算术符可以自己拷贝给自己,代码正常编译和运行都没有问题,但是在某些情况下会出现很多意想不到的情况。大家可以跟着我的思路来:


 
 
  1. data& operator=(const data& d){
  2. if( this == &d) /* check whether it is self-copy action */
  3. return * this;
  4. if(number)
  5. free(value);
  6. number = d.get_number();
  7. value = (char*)malloc(d.get_number());
  8. memmove(value, d.get_point(), d.get_number());
  9. return * this;
  10. }
    如果上面的代码没有判断复制的对象是不是自己,那么我们发现实际上value的数据实际上已经free掉了。那么此时重新分配内存,拷贝的数据只有天知道是什么数据。原来value指向的内存空间就存在了很大的不确定性,这就是算术符重载的陷阱。


【后记: 自此用汇编看C++系列全部结束,下面我们将开始数据结构和算法的讨论,欢迎关注】


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值