C++中在operator=中处理“自我赋值”(11)---《Effective C++》
来源:互联网 发布:淘宝标题营销词 编辑:程序博客网 时间:2024/05/17 22:33
条款11:在**重点内容**operator=中处理“自我赋值”
“自我赋值”发生在对象被赋值给自己时:
class Widget{…}
Widget w;
…
w=w;//赋值给自己
a[i]=a[j];//潜在的自我赋值,如果i和j有相同的值,这便是个自我赋值
*px=*py;//潜在的自我赋值,如果px和py指向同一个问题,这也是自我赋值
甚至如下这样也可以:
class Base {…};
class Derived:public Base {…};
void doSomething(const Base& rb,Derived* pd);//rb和pd可能其实是同一个对象
很多情况下“自我赋值”是安全的,不需要额外操心,然而如果你尝试自行管理资源(如果你打算写一个用于资源管理的class就这样做),可能会掉进“在停止使用资源之前以外释放了它”的陷阱,如:
class Bitmap {...};class Widget{ ...private: Bitmap* pb;};Widget& Widget::operator=(const Widget& rhs){ delete pb; pb=new Bitmap(*rhs.pb); return *this;}
这里的自我赋值问题是,operator=函数内部*this和rhs有可能是同一个对象,如果这样的话,delete pb销毁的不只是当前对象那个的bitmap,同时rhs的bitmap也被销毁掉了,那么在自我赋值的时候程序会发现rhs.pb指针指向的是一个已经被删除的对象!
如何来阻止这种错误呢,具体有多种方法:
1)传统做法是operator=最前面加一个“证同测试”达到“自我赋值”的校验目的,具体见如下代码:
Widget& Widget::operator=(const Widget& rhs){ if(this==&rhs) return *this;//证同测试 delete pb; pb=new Bitmap(*rhs.pb); return *this;}
这样的代码有没有什么错误呢?可以看到,具备了“自我赋值安全性”,那还有什么问题呢?答案就是“异常安全性”,这种解决方法对于异常并没有什么很好的作用,具体来说,如果new Bitmap(*rhs.pb)出现异常的话(不论是因为分配时内存不足或者Bitmap的copy构造函数抛出异常),pb最终指向一个被删除的Bitmap,这样的指针会出现空指针异常等乙烯类问题。
2)这种方法主要侧重于“异常安全性”方面,我们只需注意在赋值pb所指的东西之前别删除pb:
Widget& Widget::operator=(const Widget& rhs){ Bitmap* pOrig=pb; pb=new Bitmap(*rhs.pb); delete pOrig;//删除原先的pb return *thsis;}
这样的话,如果“new Bitmap”抛出异常,pb保持原状,即使没有“证同测试”,这段代码还是可以处理自我赋值,因为我们对原bitmap做了一份复件、删除原bitmap、然后指向新制造的那个复件。PS:如果此时需要考虑效率的话,需要先估计“自我赋值”发生的频率有多高?如果高的话,我们就将“证同测试”加在函数起始处?如果“证同测试”发生频率不高的话,推荐不要添加“证同测试”,因为添加这项测试也需要耗费成本,降低程序执行效率。
3)如果对上述两种方法还是不太满意的话,还有一个替代方案,不仅“异常安全”同时“自我赋值安全”,即使用copy and swap技术实现,参看以下代码:
class Widget{ ... void swap(Widget& rhs); ...};Widget& Widget::operator=(const Widget& rhs){ Widget temp(rhs);//使用copy构造函数,为rhs数据制作一份副本 swap(temp); //将*this数据和上述所述复件的数据交换 return *this;}
怎样,这种方法不错吧!但是代码看起来逻辑并没有多么清晰,这也是这种方法的缺点吧!
总结:
1)确保当前对象自我复制时operator=有良好的行为,其中包括“来源对象”和“目标对象”的地址、精心周到的语句顺序以及copy-and-swap操作;
2)确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象那个时候,其行为依然正确。
- C++中在operator=中处理“自我赋值”(11)---《Effective C++》
- 【Effective c++】条款11:在operator=中处理“自我赋值”
- 《Effective C++》学习笔记条款11 在operator =中处理“自我赋值”
- Effective C++——》条款11:在operator=中处理自我赋值
- Effective C++:条款11:在operator= 中处理“自我赋值”。
- 在operator=中处理自我赋值(Effective C++_11)
- 读书笔记《Effective C++》条款11:令operator=中处理”自我赋值“
- Effective C++ 条款11 在赋值操作符operator=中处理“自我赋值”
- 《Effect C++》学习------条款11:在 operator= 中处理“自我赋值”
- Effective C++ 学记之11 在operator=中处理“自我赋值“
- Effective C++ Item 11 在operator= 中处理“自我赋值”
- Effective C++ 读书笔记 条款11:在operator= 中处理"自我赋值"
- Effective C++ Item 11-在operator = 中处理"自我赋值"
- 读书笔记 effective c++ Item 11 在operator=中处理自我赋值
- 读书笔记 effective c++ Item 11 在operator=中处理自我赋值
- 读书笔记 effective c++ Item 11 在operator=中处理自我赋值
- 读书笔记 effective c++ Item 11 在operator=中处理自我赋值
- effective c++ Item 11 在operator=中处理自我赋值
- Codeforces Round #386 (Div. 2) 746D Green and Black Tea
- Android 阴影背景
- layer前端组件实现图片显示功能
- 用mybatis实现返回刚插入表数据记录的主键值id
- HDU-1025
- C++中在operator=中处理“自我赋值”(11)---《Effective C++》
- Docker GUI调研
- 划分树
- mme log
- react-router基本知识
- 7.18
- linux常用命令之seq
- 23. 散列表
- @property