您的位置:首页 > 编程语言 > C语言/C++

Effective C++——operator =

2015-09-18 16:48 627 查看
**

让operator = 返回一个reference to *this

**

#include <iostream>
using namespace std;

class Widget
{
public:
Widget(){}
~Widget(){}
Widget& operator=(const Widget& obj)
{
//TODO:赋值操作
return *this;
}
};

int main()
{
Widget w1,w2,w3;
w1 = w2 = w3;
cin.get();
return 0;
}


说明:Widget& operator=(const Widget& obj)函数返回值需要是类的一个引用,目的是为了支持链式编程,否则不支持连等赋值操作。

**

在operator = 中处理自我赋值

**

考虑以下自我赋值的情况

1.Widget w;

w= w;

2. a[i] = a[j];

3. *px = *py;

4. 基类和子类之间的赋值

#include <iostream>
using namespace std;
class Bitmap
{

};
class Widget
{
public:
Widget(){}
~Widget(){}
//1.缺少异常安全性
//2.缺少自我赋值安全性
Widget& operator=(const Widget& obj)

{
delete pBitmap_;
this->pBitmap_ = new Bitmap(*obj.pBitmap_);
return *this;
}

private:
Bitmap *pBitmap_;
};

int main()
{
Widget w1;
w1 = w1;

cin.get();
return 0;
}


说明:在w1 = w1 ;语句之后会发生什么?

Widget& operator=(const Widget& obj)函数内部的*this 与obj在自我赋值时是同一个对象,这样的话,delete pBitmap_执行之后会清理obj对象,this->pBitmap_ = new Bitmap(*obj.pBitmap_);这句之后获得的内容将是垃圾内容,因为被清理了。


解决方案:传统做法是进行一个identity test

//仍缺少异常安全性
Widget& operator=(const Widget& obj)
{
if(this == &obj)
{
return *this;
}
delete pBitmap_;
this->pBitmap_ = new Bitmap(*obj.pBitmap_);
return *this;
}


说明:this->pBitmap_ = new Bitmap(*obj.pBitmap_);
内存分配失败或Bitmap拷贝构造函数抛出异常,都将导致pBitmap_ 指向一片垃圾空间


如何解决这两个问题?

庆幸的是在解决了异常安全性的同时可以避免自我赋值安全性

Widget& operator=(const Widget& obj)
{
Bitmap* temp = pBitmap_;
this->pBitmap_ = new Bitmap(*obj.pBitmap_);
delete temp ;
return *this;
}


思路:异常安全性主要是因为先delete 后又拷贝指针指向的内存空间内容了,当自我赋值时就发生了错误。
现在改为后delete,但这样就容易把刚分配的内存空间给清理了,如此自然想到需要一个临时变量存储之前的指针信息。
1.Bitmap* temp = pBitmap_;  保存旧的需要清理的内存空间指针信息;
2.this->pBitmap_ = new Bitmap(*obj.pBitmap_);获得新的内存空间;此时即使是自我赋值也不会影响,因为没有delete
3.最后清理内存空间 delete temp ;
注:此时如果是自我赋值,即使没有identity test也不会出错。因为第二步指针指向的内存空间内容还是正常数据,唯一区别是指针本身数值不一样了而已。
当然,这里也可以再加上identity test验证,由于自我赋值的概率并不高,验证代码被执行可能性不大,但验证代码本身会带来测试成本,同时执行效率降低。


还有另外一种方法来满足异常安全与自我赋值条件,即copy-and-swap技术,与异常安全密切相关,不在这里继续讨论了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: