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

Effective C++ 学习笔记(8)

2015-05-27 18:33 155 查看
Term11: Handle assignment to self in operator =

1. 在=操作符内自我赋值有风险

我们可能不太会写出类似a=a这样的表达式。但如果说对于同一个对象,其使用不同的指针、引用、容器等等指向它的时候,我们就很难保证一定不会自我赋值。自我赋值的实现里,如果仅仅是类似于a.x=b.x这样的赋值,可能除了浪费性能外并没有太大的影响,真正的危险在于new、delete之类的操作。例如:

class Bitmap;

class Widget

{

...

Bitmap* pb;

};

Widget& Widget::operator=(const Widget& rhs)

{

delete pb;

pb = new Bitmap(*rhs.pb);

return *this;

}

可以看出,如果rhs就是this指向的对象,那么会出现pb指向的对象被销毁,而赋值依然是这个被销毁对象的地址。后续对这个对象的访问势必导致内存访问错误。

下面介绍几种处理方法。

2. 证同测试

就是检测到自我赋值就直接退出而不做任何工作,如下:

Widget& Widget::operator=(const Widget& rhs)

{

if(this == &rhs) return *this;

delete pb;

pb = new Bitmap(*rhs.pb);

return *this;

}
这种方法回避了自我赋值,但依然存在安全问题,如果pb = new Bitmap(*rhs.pb);开辟新空间没有成功,this->pb依然是无效的变量,访问它会导致内存错误。

3. 语序顺序控制

2中的代码是先delete再new,所以new的结果无法影响delete。如果先new,new失败了抛出异常,没有抛异常再delete,就可以避免这种情况。如下:

Widget& Widget::operator=(const Widget& rhs)

{

Bitmap* pOrig = pb;

pb = new Bitmap(*rhs.pb);

delete pOrig;

return *this;

}

4. Copy and swap

这种方法要求实现形如void Widget::swap(Widget& rhs);的方法,将rhs与*this的成员互换。代码如下:

Widget& Widget::operator=(const Widget& rhs)

{

Widget temp(rhs);

swap(rhs);

return *this;

}

由于这里调用了拷贝构造函数,可以将其简化为:

Widget& Widget::operator=(const Widget rhs)

{

swap(rhs);

return *this;

}

这种方式将直接调用拷贝构造函数改为了隐式调用。上一段代码由于是传引用,因此需要显式调用;而这里由于是传值,参数压栈时会自动调用,代码显得更加精巧。当然,这种精巧使得代码更晦涩,不见得是好事。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: