C++中赋值函数operator=潜在的“自我赋值安全性”和“异常安全性”
看下面一段代码:
class Bitmap { ... } class Widget { public: Widget& operaotr=(const Widget& wg); private: Bitmap* bp; } Widget& operator=(const Widget& wg) { delete bp; bp = new Bitmap(*wg.bp); return *this; }
上面的一段简单的赋值函数,看上去逻辑很正确:首先释放掉bp所指的当前对象,然后将其指向新的对象,并返回指向this的引用。如果仔细分析,会发现存在下面两个问题:
1)如果bp与wg的bp所指的是同一对象,那么delete bp后,wg的bp也将指向一个已经删除的对象,最终bp所指的也是一个已经删除的对象,从而出现错误。
2)如果上面的问题没有出现,但new一个Bitmap的时候出现了异常(内存分配不足或者拷贝构造函数出现异常等),那么最终得到的pb还是指向一个已经删除的对象。
为了解决上面的问题,可以先将bp指向新的对象,然后再释放掉其原来指向的对象。
例如:
Widget& operator=(const Widget& wg) { Bitmap* srbp = bp; bp = new Bitmap(*wg.bp); delete srbp; return *this; }
或者如下方法,将wg的数据制作一个副本,然后将这个副本数据与*this数据交换。
Widget& operator=(const Widget& wg) { Widget ob(wg); swap(ob); return *this; }
整理子Effective C++第3版case 11。