Effective C++ 条款10 令operator=返回一个reference to *this 条款11 在operator=中处理"自我赋值"
1. 为了支持形如“a=b=c”的连锁形式,最好令operator=返回一个reference to *this.
2. 如果类中含有用于指向堆内存的指针,那么赋值操作符就要注意自我赋值的问题,例如:
class A{ public: ... A& operator=(const A& tmp){ if (ptr != tmp.ptr){ delete ptr; ptr = new int(*tmp.ptr); } return *this; } private: int* ptr; };
以上示例虽然已经具备了"自我赋值安全性",但却不具备"异常安全性":如果"new int(*tmp.ptra)"发生异常,被赋值的ptra将指向一个已经被delete的对象,因此为了实现异常安全性,应该保证先赋值再delete,如下:
class A{ public: ... A& operator=(const A& tmp){ int* temp = ptr;//临时储存ptr的值 ptr = new int(*tmp.ptr); delete temp; return *this; } private: int* ptr; };
以上保证了异常安全性的同时也保证了自我赋值的安全性,缺点是自我赋值虽然是安全的,但是却进行了不必要的申请内存和复制,如果自我赋值频率确实很高,可以把"证同测试“再次放回函数起始处.
3. 像上例一样在operator=内部手工排列语句的一个替代方案就是使用所谓的"copy and swap"技术,这个技术和异常安全性有密切关系(见条款29),如下:
class A{ public: void swap(A& rhs){ ... } A& operator=(A tmp){//注意此处按值传递 A temp(tmp); swap(temp); } private: int* ptr; };
这样牺牲了清晰性而且比之前的例子多了一次对象构造,但采用按值传递实际上"将'copying'动作从函数本体移至'函数参数构造阶段'",这"可令编译器有时生成更高效的代码".
4. 不只是赋值操作符,其它函数如果要操作一个以上对象,而其中有些对象可能是同一个时,也要确保函数行为的正确性.