Effective C++ 学习笔记(8)

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;

}

这种方式将直接调用拷贝构造函数改为了隐式调用。上一段代码由于是传引用,因此需要显式调用;而这里由于是传值,参数压栈时会自动调用,代码显得更加精巧。当然,这种精巧使得代码更晦涩,不见得是好事。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值