effective C++ 读书笔记 条款11
条款11: 在operator= 中处理“自我赋值”
在实现operator=时考虑自我赋值是必要的就像 x=y ,我们不知道变量x与y代表的值是否为同一个值(把x和y说成是一个指针更恰当一点)。如下
第一版:
#include <iostream> using namespace std; class bitmap { public: bitmap() { cout<<"调用bitmap()无参构造函数"<<endl; } bitmap(const bitmap& bt) { this->i = bt.i; cout<<"调用bitmap()拷贝构造函数"<<endl; } ~bitmap() { } private: int i; }; class Widget { public: Widget() { pb = new bitmap(); } Widget(const Widget& wd) { this->pb = wd.pb; } public: Widget& operator=(const Widget& rhs); private: bitmap* pb; //定义一个从heap分配而得的对象 }; //第一版赋值函数: Widget& Widget::operator=(const Widget& rhs) { delete pb; pb = new bitmap(*rhs.pb); return *this; } //这一版函数的pb在使用前清理掉之前的pb指向,再接受一个new出来的新对象,看着很顺理成章,但是 //当this与函数参数rhs相等的时候,pb = new bitmap(*rhs.pb);因为我们已经把*rhs.pb delete掉了。 int main() { Widget w1; Widget w2; w1 = w2; return 0; } /* 调用bitmap()无参构造函数 调用bitmap()无参构造函数 调用bitmap()拷贝构造函数 Press any key to continue */
第二版:
//第二版赋值函数: Widget& Widget::operator=(const Widget& rhs) { if (this == &rhs) { return *this; } delete pb; pb = new bitmap(*rhs.pb); return *this; } //这个版本行的通,赋值函数基本上是可以接受的,但是不见得是安全的,因为当new产生异常时pb依然是一个 //不确定的指针。
第三版:
//第三版赋值函数: Widget& Widget::operator=(const Widget& rhs) { bitmap *pOrig = pb; pb = new bitmap(*rhs.pb); delete pOrig; return *this; } //第三版函数在开始的时候用pOrig记录了pb,当new没有异常时我们再把pb原来的指向空间释放掉 //从而提高了安全性。这种方法也同样能够处理自我赋值,假如这里rhs=*this;我们先对原来的 //bitmap做了一份备份,删除原bitmap后,指向了我们的那一份备份,或许这种处理自我赋值的方法 //不是很好,但是行的通,在保证安全性的情况下采用这种办法很不错。
第四版:
#include <iostream> using namespace std; class bitmap { public: bitmap() { cout<<"调用bitmap()无参构造函数"<<endl; } bitmap(const bitmap& bt) { this->i = bt.i; cout<<"调用bitmap()拷贝构造函数"<<endl; } ~bitmap() { } private: int i; }; class Widget { public: Widget() { cout<<"调用Widget()无参构造函数"<<endl; pb = new bitmap(); } Widget(const Widget& wd) { cout<<"调用Widget()拷贝参构造函数"<<endl; this->pb = wd.pb; } void my_swap(Widget& rhs); public: Widget& operator=(const Widget& rhs); private: bitmap* pb; //定义一个从heap分配而得的对象 }; //第四版赋值函数: void Widget::my_swap( Widget& rhs) { pb = rhs.pb; } Widget& Widget::operator=(const Widget& rhs) { Widget temp(rhs);//防止改变rhs my_swap(temp); return*this; } //第四版赋值函数利用的是copy and swap技术,这个技术在条款29当中 //有详细说明,还没认真看,这里就不解释了。 //第四版也可以这样用: Widget& Widget::operator=(Widget rhs) { my_swap(rhs); //其实本质上是一样的,因为传递的参数是值传递,所以这里传递的是rhs的一个副本,相当于Widget temp(rhs);主要就是防止rhs被改变; return*this; } int main() { Widget w1; Widget w2; w1 = w2; return 0; } /* 调用Widget()无参构造函数 调用bitmap()无参构造函数 调用Widget()无参构造函数 调用bitmap()无参构造函数 调用Widget()拷贝参构造函数 Press any key to continue */
总结:
1:确保当对象自我赋值时 operator= 有良好行为,其中技术包括比较“原来对象”和“目标对象”的地址。、精心周到的语句顺序,以及copy and swap
2:确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。