effective c++条款11

在 operator= 中处理自我赋值

自我赋值发生在对象被赋值给自己时,比如w=w,但是更多的是隐性的自我赋值(不能一下子看穿的)
如果i=j,那么a[i]=a[j]算不算自我赋值呢
假设有这么一段代码

class Bitmap {...}
class Widget
{
public:
    ...
private:
    Bitmap* pb;
}

//下面是operator=的代码
Widget& Widget::operator=(const Widget& rhs)
{
    delete pb;
    pb=new Bitmap(*rhs.pb);
    return *this
}

这段operator=的代码没有考虑到this==&rhs
当this==&rhs时,pb早已经被释放了,这样new Bitmap就会因为发现异常而不会生效,其结果是this->pb指向了一个已经删除的对象

解决方法很简单:加个证同测试

Widget& Widget::operator=(const Widget& rhs)
{
    if(this==&rhs)
        return *this;
    delete pb;
    pb=new Bitmap(*rhs.pb);
    return *this
}

这个方法基本可行,但还是会存在问题,当new操作发生异常时(此时代码就不会往下执行),pb还是会指向一个已经被删除了的对象,这说明这种方法没有”异常安全性”

解决方法是,不考虑证同测试(证同测试会降低代码执行速度),new之后再删除原来的指针
就像下面这样

Widget& Widget::operator=(const Widget& rhs)
{
    Bitmap* pOrg=pb;//保存原始的this指针
    pb=new Bitmap(*rhs.pb);//将新的对象赋值给this
    delete pOrg;//删除原来的指针
    return *this
}

这个代码的好处是具备”异常安全性”和”自我赋值安全性”
1.当new操作发生问题时,operator=将会停止往下执行,pb会维持原来的值
2.当this==&rhs时,我们忽略它们是同一个对象的事实,创建一份rhs的副本赋给this,然后删除原始的this对象

当然还有更”骚”的操作:参数传入时byValue,我们知道,byValue时,形参会复制实参的数据,这样就把创建副本的工作交给了构造函数,比如下面这样

Widget& Widget::operator=(const Widget rhs)
{
    Bitmap* pOrg=pb;//保存原始的this指针
    pb=&rhs;//将新的对象赋值给this
    delete pOrg;//删除原来的指针
    return *this;
}

猜你喜欢

转载自blog.csdn.net/baidu_25539425/article/details/79928223