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

自我赋值的一些情况:

①最明显的不过于x=x这种自我赋值。

②arr[i]=arr[j],如果i=j这就是一个潜在的自我赋值。

③对于不同的指针或者不同的引用表示着同一空间,这个时候也容易产生自我赋值,看下面的例子

    int x = 10;
    int *p = &x;
    int *p1 = &x;
    int &pp = x;
    int &ppp = x;
    *p = *p1;//自我赋值
    pp = ppp;//自我赋值

④对于继承体系中也容易产生潜在的自我赋值的情况,因为基类对象的指针和引用可以指向子类对象。例子如下:

class Base{};
class Dervice :public Base{};
void fun(const Base& s,Dervice *p)

上面这种情况s和p就容易是同一个对象,从而存在自我赋值的隐患。


用智能指针可以不用担心自我赋值引起的安全问题。

如果没有智能指针需要自己控制(重写赋值运算符重载函数),那该怎样做?

①首先看这么一个类的形式

class A{};
class B
{
private:
    A *pt;
};
如果在B的operator=函数中这么实现
B& B::operator=(const B& s)
{
    delete _pt;//删除原来的空间
    _pt = new A(*s._pt);//创建一个*s._pt的副本
    return *this;
}

在这个里面存在自我赋值的情况,即*this和s是一个对象的话,那么delete _pt就不仅仅是销毁当前对象的A对象了,他也销毁了s持有的A对象,那么就会造成自己所持有的指针指向了一个被删除的对象
对于这种问题的解决其实很简单,直接在最前面加上判同语句就可以了

B& B::operator=(const B& s)
{
    if (this == &s)
        return *this;
    delete _pt;//删除原来的空间
    _pt = new A(*s._pt);
    return *this;
}

这样就避免了自我赋值所产生的问题。

但是这样存在新的问题,比如在new A(*s._pt)的时候抛出了异常,那么_pt就会指向一个被删除的空间。这样的指针是存在很大问题的。你唯一能做的就是慢慢调试去找产生异常的bug吧。所以就又有了下面的版本

B& B::operator=(const B& s)
{
    A *p = _pt;//保存A类对象的备份
    _pt = new A(*s._pt);
    delete p;//删除原来的A类的对象
    return *this;
}

这段代码我们开始先拷贝一份B类中的成员变量A,紧接着通过new拷贝s的数据,假如此时new失败了,原来的一切还保持不变,假如成功了释放掉p所指向的内存。


除了②的这种写法还有下面这种方式,就是加入swap,这个swap你可以自己写也可以用库里面的。

void B::swap(B& rhs)
{
    //交换*this和rhs的数据。
}
B& B::operator=(const B& s)
{
    B tmp(s);//用s创建一份临时的对象tmp,出了这个作用域自动被销毁
    swap(tmp);//通过tmp将s和*this的值交换
    return *this;
}


这种写法还可以演变为下面的这种写法,即将传引用变为传值

void B::swap(B& rhs)
{
    //交换*this和rhs的数据。
}
B& B::operator=( B s)
{
    swap(s);//s和*this的值交换
    return *this;
}

最既然需要临时对象,索性就采用值传递的方式,传入实参后自动创建一个副本,这个副本就是临时对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搓搓程序狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值