NO.10: 在operator=中处理 "自我赋值"
1.确保当对象自我赋值时operator=有良好的行为,其中的技术包括 "来源对象" 和 "目标对象" 的地址,精心周到的语句顺序,以及“ copy and swap ” 技术
2.确定任何函数执行操作一个以上对象时,而其中多个对象是同一个对象时,其行为任然正确
1 #include <iostream> 2 3 4 //1.0 5 class CopySwap1_0 6 { 7 private: 8 int *value; 9 public: 10 CopySwap1_0() : value(new int(200)) 11 {} 12 13 ~CopySwap1_0() 14 { delete value; }; 15 16 //不符合 "C++异常安全" 1.没有考虑自赋值情况. 2.new抛出异常的话,原数据销毁 17 CopySwap1_0 &operator=(const CopySwap1_0 &rhs) 18 { 19 delete value; 20 value = new int(*rhs.value); 21 return *this; 22 23 } 24 25 }; 26 27 //2.0 28 class CopySwap2_0 29 { 30 private: 31 int *value; 32 public: 33 CopySwap2_0() : value(new int(200)) 34 {} 35 36 ~CopySwap2_0() 37 { delete value; }; 38 39 //保证异常安全,和自赋值情况,但执行效率可以提高 40 CopySwap2_0 &operator=(const CopySwap2_0 &rhs) 41 { 42 if (this == &rhs) return *this; 43 44 int *temp = value; 45 value = new int(*rhs.value); 46 delete temp; 47 return *this; 48 } 49 50 }; 51 52 53 //3.0 54 class CopySwap3_0 55 { 56 friend void swap(CopySwap3_0& lhs,CopySwap3_0& rhs); 57 private: 58 int *value; 59 public: 60 CopySwap3_0() : value(new int(200)) 61 {} 62 63 ~CopySwap3_0() 64 { delete value; }; 65 66 CopySwap3_0(const CopySwap3_0& rhs) 67 { 68 value=new int(*rhs.value); 69 //other work 70 } 71 72 73 //这样做我们会失去一个重要的优化机会 74 //通常,我们最好遵循比较有用的规则是:不要拷贝函数参数。你应该按值传递参数,让编译器来完成拷贝工作。 75 76 // CopySwap3_0 &operator=(const CopySwap3_0 &rhs) 77 // { 78 // CopySwap3_0 lhs(rhs); 79 // std::swap(*this, lhs); 80 // return *this; 81 // 82 // } 83 84 85 // 这种管理资源的方式解决了代码冗余的问题,我们可以用拷贝构造函数完成拷贝功能,而不用按位拷贝。拷贝功能完成后,我们就可以准备交换了。 86 // 注意到,上面一旦进入函数体,所有新数据都已经被分配、拷贝,可以使用了。这就提供了强烈的异常安全保证:如果拷贝失败,我们不会进入到函数体内, 87 // 那么this指针所指向的内容也不会被改变。(在前面我们为了实施强烈保证所做的事情,现在编译器为我们做了)。 88 // swap函数时non-throwing的。我们把旧数据和新数据交换,安全地改变我们的状态,旧数据被放进了临时对象里。这样当函数退出时候,旧数据被自动释放。 89 // 因为copy-and-swap没有代码冗余,我们不会在这个而操作符里面引入bug。我们也避免了自我赋值检测。 90 91 CopySwap3_0 &operator=(CopySwap3_0 rhs) 92 { 93 swap(*this, rhs); 94 return *this; 95 96 } 97 98 99 }; 100 101 102 void swap(CopySwap3_0& lhs,CopySwap3_0& rhs) 103 { 104 //using声明现在当前作用域寻找swap,没有则使用std::swap 105 using std::swap; 106 swap(lhs.value,rhs.value); 107 //其他指针/值操作 108 } 109 110 111 int main(int argc, char **argv) 112 { 113 CopySwap3_0 A, B; 114 A = B; 115 return 0; 116 }
Toal:一般具有管理资源分配的类使用copy and swap,效益是最好的,copy and swap 使用一次拷贝构造和析构操作换取一次拷贝赋值操作(往往拷贝赋值操作也是执行析构和拷贝操作),对于数据变量结点少的情况copy and swap是最好的,也防止自赋值和异常问题,对于资源分配的类最好实现自己的swap函数,防止循环调用赋值运算符- -;