条款11(二):在operator= 中处理“自我赋值”

127 篇文章 7 订阅
39 篇文章 3 订阅

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

Handle assignment to self in operator=.

异常安全性与自我赋值安全性

接上一篇,当我们让operator= 具备“异常安全性”时,往往会自动获得“自我赋值安全性”的特性。
因此,很多时候,并不专门去解决“自我赋值”的问题,而是将注意力放在“异常安全性(exception safety)”之上。例如对于下面,只需要注意在赋值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(及其栖身的那个Widget)也会保持原状。即使没有证同测试,这段代码也是能够处理自我赋值问题:

  • 为原bitmap创建一份复件
  • 删除原bitmap
  • 指向这个新制造的复件

虽然可能这种方法不是处理“自我赋值”最有效的方法,但是确实是一种可行解。

当然,如果我们想要提高效率,也可以将证同测试重新放到函数的起始处。

Copy and Swap

另外,在operator=函数内为了确保代码“异常安全性”与“自我赋值安全性”而手工排列语句的替代方案则是:

  • 使用copy and swap技术。

这个技术和“异常安全性”密切相关:

class Widget {
...
void swqp(Widget& rhs);   //交换*this和rhs的数据
...
};

Widget& Widget::operator=(const Widget& rhs)
{
    Widget temp(rhs);      //为rhs数据制作一份复件
    swap(temp);            //将*this数据和上述的复件进行数据交换
    return *this;
}

然而,这种方法的另一种更为高效简洁的写法为:

Widget& Widget::operator=(Widget rhs)   //rhs直接就是被传对象的一份复件,此时是pass by value
{
    swap(rhs);           //将*this数据和上述的复件进行数据交换
    return *this;
}

这种方法之所以可以,是因为:

  • 某class的copy assignment操作符可能被声明为“以by value方法接受实参”
  • 以by value方法传递东西会形成一份复件。

这种方法牺牲了代码的清晰性,但是却将“copy动作”从函数本体内移至“函数参数构造阶段”,使得编译器生成了更有效的代码。

最后:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值