11:在operator=中处理“自我赋值”

“自我赋值”发生在对象被赋值给自己时:

class Widget{};
Widget w;
w=w;//赋值给自己

对于operator=,当类用一个指针指向一块动态分配的内存时,若调用operator=,当不对“自我赋值” 进行处理,可能会产生错误:

class Bitmap{};
class Widget{
public:
    Widget& operator=(const Widget& rhs);
private:
    Bitmap *pb;
};
//下面是一份不安全的operator实现版本
Widget& Widget::operator=(const Widget& rhs)
{
    delete pb;//停止使用当前的Bitmap
    pb=new Bitmap(*rhs.pb);//使用rhs的bitmap副本
    return *this;
}

存在的自我赋值问题是,operator=函数内的*this(赋值目的端)和rhs可能是同一个对象。若是如此,则delete就不只是销毁当前对象的bitmap,它也销毁了rhs的bitmap。此时,widget中的指针指向了一个已被删除的对象。 

解决这个问题的传统方法是在operator=最前面进行“证同测试”:

Widget& Widget::operator=(const Widget& rhs)
{
    if(this==&rhs)//当指向同一对象时,不进行赋值
        return *this;
    delete pb;//停止使用当前的Bitmap
    pb=new Bitmap(*rhs.pb);//使用rhs的bitmap副本
    return *this;
}

但此版本也存在一个问题,若new Bitmap发生异常(因为分配时内存不足或Bitmap的copy构造函数抛出异常),最终Widget会持有一个指针指向一块已被删除的Bitmap。无法安全地删除这样的指针,也无法安全地读取它们。

另外一个版本,只需注意在复制pb所指东西之前别删除pb:

Widget& Widget::operator=(const Widget& rhs)
{
    Bitmap* pOrig=pb;//记住原先的pb
    pb=new Bitmap(*rhs.pb);//令pb指向*pb的一个副本
    delete pOrig;//删除原先的pb
    return *this;
}

对于此版本来说,即使new Bitmap抛出异常,pb也会保持原状,这段代码也能处理自我赋值的问题。

总结

1.确保当对象自我赋值时operator=有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。

2.确定任何函数如果操作一个以上的对象,而其中多个对象是同一对象时,其行为仍然正确。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值