当前位置: 首页 > article >正文

Effective C++读书笔记——item11(自赋值)

自赋值相关问题

  1. 自赋值情况示例
    • 明显的自赋值如w = w,还有不太容易辨别的情况,像a[i] = a[j](当ij值相同)、*px = *py(当pxpy指向同一对象)等,这些是由别名(有多种引用对象的方式)造成的,尤其在涉及引用、指针操作同类型多个对象以及继承体系中基类和派生类对象引用、指针转换时要考虑自赋值可能。
  2. 自赋值在资源管理类中的隐患
    • Widget类持有指向动态分配位图的裸指针pb为例,若operator=实现时未考虑自赋值情况,像最初不安全的实现:先delete pbnew Bitmap(*rhs.pb),当*thisrhs是同一个对象时,会导致删除了不该删除的资源(同时破坏了rhs的资源),最终使对象持有指向已删除对象的 “有毒” 指针。
    • Widget&
      Widget::operator=(const Widget& rhs)              // unsafe impl. of operator=
      {
        delete pb;                                      // stop using current bitmap
        pb = new Bitmap(*rhs.pb);                       // start using a copy of rhs's bitmap
      
        return *this;                                   // see Item 10
      }
  3. 传统防止自赋值错误的方法及局限
    • 传统方法是在operator=开始处通过if (this == &rhs) return *this;进行一致性检测,若为自赋值则直接返回。但此方法只解决了自赋值安全问题,对于之前提到的operator=版本,其还存在异常不安全的问题,例如new Bitmap表达式引发异常时,会导致对象持有指向已删除位图的指针,后续无法安全处理。

兼顾异常安全与自赋值安全的方法

  1. 调整语句顺序
    • 通过先保存原指针指向的数据(如Bitmap *pOrig = pb;),再进行新数据的拷贝(pb = new Bitmap(*rhs.pb);),最后删除原数据(delete pOrig;)的语句顺序调整,能在保证异常安全的同时处理自赋值情况,即使new Bitmap抛出异常,对象原有状态也不会被破坏,且无需一致性检测,但可能不是最有效率的做法。
      ​
      Widget& Widget::operator=(const Widget& rhs)
      {
        Bitmap *pOrig = pb;               // remember original pb
        pb = new Bitmap(*rhs.pb);         // make pb point to a copy of *pb
        delete pOrig;                     // delete the original pb
      
        return *this;
      }
      
      ​

  2. 使用 “copy and swap” 技术
    • 涉及类中定义swap函数交换数据,一种实现是先创建参数对象的副本(Widget temp(rhs);),再通过swap(temp)交换*this和副本的数据;另一种变种是将operator=参数以传值方式接收(Widget& Widget::operator=(Widget rhs)),函数内直接swap(rhs)交换数据,后者在一定程度上可能让编译器产生更有效率的代码,但清晰度可能稍受影响。
    • class Widget {
        ...
        void swap(Widget& rhs);       // exchange *this's and rhs's data;
        ...                           // see Item 29 for details
      };
      
      Widget& Widget::operator=(const Widget& rhs)
      {
        Widget temp(rhs);             // make a copy of rhs's data
      
        swap(temp);                   // swap *this's data with the copy's
        return *this;
      }
      
      Widget& Widget::operator=(Widget rhs)   // rhs is a copy of the object
      {                                       // passed in — note pass by val
      
        swap(rhs);                            // swap *this's data with
                                              // the copy's
        return *this;
      }

总结与注意事项

在编写代码时要确保operator=等操作多个对象的函数在对象自赋值或对象相同时行为良好,处理自赋值问题的技巧包括比较源和目标对象地址、关注语句顺序、使用 “copy and swap” 等方法,并且要根据实际情况权衡效率、代码清晰度等因素来选择合适的方式。


http://www.kler.cn/a/471281.html

相关文章:

  • [Linux]redis5.0.x升级至7.x完整操作流程
  • (六)CAN总线通讯
  • 面向对象的思维hong
  • 121 买入股票的最佳时机
  • 「Mac畅玩鸿蒙与硬件53」UI互动应用篇30 - 打卡提醒小应用
  • 30、论文阅读:基于小波的傅里叶信息交互与频率扩散调整的水下图像恢复
  • Python中判断语句及循环语句练习
  • 对于安装完服务后,无法执行命令的问题处理
  • 行为树详解(6)——黑板模式
  • halcon三维点云数据处理(五)创建代表工具和机器人底座的3D模型
  • Qt仿音乐播放器:客户端唯一化
  • 使用 httputils + chronicle-bytes 实现金融级 java rpc
  • 【免费】2004-2019年各省规模以上工业企业RD经费面板数据
  • RabbitMQ-死信队列
  • android系统的一键编译与非一键编译 拆包 刷机方法
  • 【数据可视化】数据可视化看板需求梳理模板(含示例)
  • Linux 系统清理命令大全
  • 深度学习中的正则化方法
  • React 深入学习理解
  • Redis Zset有序集合
  • python学opencv|读取图像(二十七)使用cv2.warpAffine()函数平移图像
  • Unity中 Xlua使用整理(一)
  • nginx 配置 本地启动
  • 移动应用安全基础:深入理解Hooking框架
  • cuda实现flash_attn_mma_share_kv源码分析
  • vue el table 不出滚动条样式显示 is_scrolling-none,如何修改?