NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
## 条款11:在 operator= 中处理自我赋值 Handle assignment to self in operator=. ### 潜在的自我赋值以及危害 自我赋值并不容易被肉眼辨别: ```cpp a[i] = a[j]; *px = *py; ``` 一份不安全的复制函数实现: ```cpp Widget& Widget::operator=(const Widget& rhs) { delete pb; pb = new Bitmap(*rhs.pb); // 如果是自我赋值,此时 *rhs.pb 指向的空间已经被释放; return *this; } ``` ### 解决办法 传统做法是证同测试(identity test): ```cpp Widget& Widget::operator=(const Widget& rhs) { if (this == &rhs) return *this; // 证同测试; delete pb; pb = new Bitmap(*rhs.pb); return *this; } ``` 但是这个版本不具备异常安全性(exception safety),即当 `new Bitmap` 出现异常时,`pb` 会指向一个被删除的空间,为此可以将重点放到实现异常安全性上: ```cpp Widget& Widget::operator=(const Widget& rhs) { Bitmap* pOrig = pb; // 记住原先的 pb; pb = new Bitmap(*rhs.pb); // 令 pb 指向一个副本; delete pOrig; // 删除原先的 pb; return *this; } ``` 这种做法虽然会造成额外的性能开销,但是却解决了自我赋值和异常安全的问题。如果程序很关心性能,可以加上证同测试,但这将引入一个新的控制流分支(control flow),它同样会降低执行速度。