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函数,防止循环调用赋值运算符- -;

原文地址:https://www.cnblogs.com/xuaidongstdudyrecording/p/7260431.html