在operator = 中处理“自我赋值”“自我赋值”时常很容易被修正。

但下面的情况:

a[i] = a[j];
*px = *py;

如果i = j, px和py都指向同一个对象,就会出现“自我赋值”。

有如下类:

class Bitmap { ... };
class Widget
{public:Widget& operator = (const Widget& rhs);
...private:Bitmap* pb; // 指向堆内存
}

对于如下operator = 实现:

Widget& Widget::operator = (const Widget& rhs)
{delete pb;pb = new Bitmap(*rhs.pb);return *this;
}

看起来合情合理,但是存在问题。
如果出现“自我赋值”,即 *this等于rhs, delete pb等同于delete rhs.pb。

可以加上“证同测试”:

Widget& Widget::operator = (const Widget& rhs)
{if (this == &rhs) return *this; delete pb;pb = new Bitmap(*rhs.pb);return *this;
}

这样就具备了“自我赋值安全”,但任存在“异常安全性”问题。
如果new Bitmap导致异常,目标对象将持有一个已被销毁的pb指针。

令人高兴的是,让operator = 具备“异常安全性”往往自动获得“自我赋值安全”的回报。

一种合适办法是:

Widget& Widget::operator = (const Widget& rhs)
{Bitmap* pOrig = pb;pb = new Bitmap(*rhs.pb);delete pOrig;return *this;
}

如果Bitmap抛出异常,由于pb还未delete,因此不会有问题。
即使没有“证同测试”, 依然没有问题, 因为使用了pOrig保存了pb。

还有一种叫做copy and swap的技术:

class Widget
{public:void Swap(Widget& rhs); // 交换*this和rhs的数据
...
}Widget& Widget::operator = (const Widget& rhs)
{Widget temp(rhs); // 为rhs数据制作一件复件Swap(temp); // 将*this数据和上述复件的数据交换return *this;
}

其实,这段代码还有优化空间,请移步:copy-and-swap idiom详解和实现安全自我赋值

请记住:

  • 确保当对象自我赋值时operator = 有良好行为。其中技术包括比较“来元对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。

  • 确保任何函数如果操作一个以上的对象,而其中多个对象时同一个对象时, 其行为依然正确。

11.Handle assignment to self in operator =相关推荐

  1. Effective C++ 读书笔记之Part2.Constructors, Destructors, and Assignment Operators

    5.Know what functions C++ silently writes and calls. 总结:编译器可以暗自为class创建default构造函数.copy构造函数.copy ass ...

  2. Effective C++ 改善55个方法

    美·Scott Meyers 候捷 电子工业 2011 刚才看到个会议时间有点晚,3.25论文都提交了 谷歌去广告的插件, 最后投了这个会议,刚刚好正合适.我说金钱与时间 ACCUSTOMING YO ...

  3. Effective C++读书笔记 摘自 pandawuwyj的专栏

    Effective C++读书笔记(0)       Start   声明式(Declaration):告诉编译器某个东西的名称和类型,但略去细节.   std::size_t numDigits(i ...

  4. Effective C++ 中文版(第三版)读书笔记 更新ing~

    Effective C++ 中文版(第三版)持续更新ing 让自己习惯C++ 条款1 视c++为一个联邦 条款2 尽量以const,enum,inline替换#define 条款3 尽可能使用cons ...

  5. Effective C++知识点

    条款01:视C++为一个语言联邦(View C++ as a federation of languages.) 对于内置类型而言,pass-by-value通常比pass-by-reference高 ...

  6. Effective C++改善程序与设计的55个具体做法笔记

    Scott Meyers大师Effective三部曲:Effective C++.More Effective C++.Effective STL,这三本书出版已很多年,后来又出版了Effective ...

  7. 【C++】C++11新增关键字详解

    目录 一.auto 1.auto 用来声明自动变量,表明变量存储在栈(C++11之前) 2.auto用于推断变量类型示例(C++11) 3.声明或定义函数时作为函数返回值的占位符,此时需要与关键字 d ...

  8. C++11 新特性简介

    1.auto auto是旧关键字,在C++11之前,auto用来声明自动变量,表明变量存储在栈,很少使用.在C++11中被赋予了新的含义和作用,用于类型推断. auto关键字主要有两种用途:一是在变量 ...

  9. C++11 新关键字

    文章目录 1.auto 1.1 用法示例 2.using 3.decltype 3.1 decltype 推导规则 3.2 用法示例 4.nullptr_t 与 nullptr 5.constexpr ...

  10. C++11中,对于deleted函数

    C++11中,对于deleted函数,编译器会对其禁用,从而避免某些非法的函数调用或者类型转换,从而提高代码的安全性. 对于 C++ 的类,如果程序员没有为其定义特殊成员函数,那么在需要用到某个特殊成 ...

最新文章

  1. Jerry Wang 2014年1月3日top liked SCN博客
  2. linux查看openssh和openssl版本命令
  3. org.xml.sax.SAXParseException: Failed to read schema document错误的完美解决方法 以及 Spring如何加载XSD文件
  4. Linux系统安装yum源报错256,Redhat Linux RHEL6配置本地YUM源及错误处理
  5. java数组 js数组的长度_js中split()方法得到的数组长度问题
  6. Asp.net性能优化-提高ASP.Net应用程序性能的十大方法
  7. 从零开始学习python编程-从零开始的Python学习 -- 简单的练习题
  8. Zephyr调整Main栈大小
  9. java太大太重_Java 编码最容易疏忽的 10 大问题!
  10. app接码教程,附源码
  11. OpenDRIVE:学习文档
  12. 方正璞华入选“火炬智能制造服务商”和“智能制造产品服务”!
  13. 通过Vue+flvjs在HTML5中播放flv格式视频文件—demo及api
  14. Tracup已证明,高效敏捷的沟通与协作可提升IT生产力
  15. 打印机怎么选择双面打印,支持双面打印资料的平台
  16. 设置首字母大写(js)
  17. 因果推断杂记——因果推断与线性回归、SHAP值理论的关系(十九)
  18. 资料搜集-JAVA系统的梳理知识
  19. Python 多元线性回归实例
  20. 从光学成像到计算光学成像

热门文章

  1. DevExpress v18.1新版亮点——WPF篇(一)
  2. 聊聊kafka consumer offset lag的监控
  3. 11月22日学习内容整理:bootstrap居中处理和组件,常用组件
  4. 《CCNP ROUTE 300-101认证考试指南》——2.10节 复习所有考试要点
  5. Maven 打包错误:%JAVA_HOME%/../lib/tools.jar
  6. B22-SVN在iOS开发的使用中遇到的问题
  7. 札记 - PHP/JS/jQuery/MySQL/CSS/正则/Apache
  8. OLEDB SqlHelper
  9. 30.yii2 --- 全文检索简介
  10. 114. PHP command line getopt