本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie
经验:确保当对象自我赋值时operator=有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。
示例:没有“证同测试”
#include <iostream>
#include <string>
using namespace std;
class Bitmap{
public:
Bitmap(int s):size(s){}
Bitmap(const Bitmap &b){
this->size = b.size;
}
int getSize() const{return size;}
private:
int size;
};
class Widget{
public:
Widget(int size){
pb = new Bitmap(size);
}
Widget &Widget::operator=(const Widget &rhs){
delete pb; //停止使用当前的bitmap
pb = new Bitmap(*rhs.pb); //使用rhs's bitmap的副本
return *this;
}
Bitmap *getBitMap() const{return pb;}
private:
Bitmap *pb; //指针,指向一个从heap分配而得的对象
};
int main(){
Widget w(1);
cout << "before self assignment: " << w.getBitMap()->getSize() << endl;
w = w;
cout << " after self assignment: " << w.getBitMap()->getSize() << endl;
system("pause");
}
输出:
before self assignment: 1
after self assignment: -842150451
解析:
operator=函数内的*this和rhs是同一个对象,delete销毁当前对象的bitmap,也销毁了rhs的bitmap,在函数末尾,Widget用自己持有一个指向已被删除的对象指针创建新的bitmap。所以当自我赋值后,w对象里的值变成了乱码。
纠正1:通过“证同测试”来避免自我赋值
示例:加了“证同测试”
#include <iostream>
#include <string>
using namespace std;
class Bitmap{
public:
Bitmap(int s):size(s){}
Bitmap(const Bitmap &b){
this->size = b.size;
}
int getSize() const{return size;}
private:
int size;
};
class Widget{
public:
Widget(int size){
pb = new Bitmap(size);
}
Widget &Widget::operator=(const Widget &rhs){
if(this == &rhs) return *this; //这里加了“证同测试”
delete pb;//停止使用当前的bitmap
pb = new Bitmap(*rhs.pb); //使用rhs's bitmap的副本
return *this;
}
Bitmap *getBitMap() const{return pb;}
private:
Bitmap *pb; //指针,指向一个从heap分配而得的对象
};
int main(){
Widget w(1);
cout << "before self assignment: " << w.getBitMap()->getSize() << endl;
w = w;
cout << " after self assignment: " << w.getBitMap()->getSize() << endl;
system("pause");
}
输出:
before selfassignment: 1
after self assignment: 1
纠正2:通过处理“异常安全性”来自动获得“自我赋值安全”的回报
#include <iostream>
#include <string>
using namespace std;
class Bitmap{
public:
Bitmap(int s):size(s){}
Bitmap(const Bitmap &b){
this->size = b.size;
}
int getSize() const{return size;}
private:
int size;
};
class Widget{
public:
Widget(int size){
pb = new Bitmap(size);
}
Widget &Widget::operator=(const Widget &rhs){
Bitmap* pOrig = pb; //记住原先的pb
pb = new Bitmap(*rhs.pb); //使用rhs's bitmap的副本
delete pOrig; //删除原先的pb
return *this;
}
Bitmap *getBitMap() const{return pb;}
private:
Bitmap *pb; //指针,指向一个从heap分配而得的对象
};
int main(){
Widget w(1);
cout << "before self assignment: " << w.getBitMap()->getSize() << endl;
w = w;
cout << " after self assignment: " << w.getBitMap()->getSize() << endl;
system("pause");
}
输出:
before selfassignment: 1
after self assignment: 1
解析:如果“newBitmap”抛出异常,pb保持原状;这段代码也能处理自我赋值。还可以把“证同测试”再次放回函数起始处,双重保险,不过有其他执行速度等的代价
纠正3:copy and swap技术
示例:
<pre name="code" class="cpp"> Widget &Widget::operator=(const Widget &rhs){
Widget temp(rhs);
swap(temp);
return *this;
}
或
Widget &Widget::operator=( Widget rhs){ //将”copying动作”从函数本体移到“函数参数构造阶段”
swap(rhs);
return *this;
}