zoukankan      html  css  js  c++  java
  • 【C++】自我赋值问题

    首先通过一个例子引出自我赋值可能会导致的问题,例子如下:

     1 class Bitmap {...};
     2 class Widget {
     3 public:
     4     ...
     5     Widget& operator=(const Widget& rhs);
     6     ...
     7 private:
     8     Bitmap* pb;
     9 };
    10 Widget& Widget::operator=(const Widget& rhs)    //一份不安全的operator=实现版本
    11 {
    12     delete pb;
    13     pb = new Bitmap(*rhs.pb);
    14     return *this;
    15 }

    由于Widget类包含动态分配对象的指针,因而需要自定义拷贝构造函数和赋值符函数.

    在上述operator=函数中,如果*this(赋值的目的端)和rhs是同一个对象,将会导致*this对象里的pb指针指向一个已被删除的对象.

    通过在operator=中增加一个证同测试,可以阻止这种错误.代码实现如下:

    1 Widget& Widget::operator=(const Widget& rhs)    
    2 {
    3     if(this == &rhs)        //证同测试
    4         return *this;    
    5     delete pb;
    6     pb = new Bitmap(*rhs.pb);
    7     return *this;
    8 }

    虽然增加证同测试后,可以达到自我赋值的安全性,但不具备异常安全性.

    如果"new Bitmap"导致异常,Widget最终会持有一个指针指向一块被删除的Bitmap

    这样的指针有害,我们无法安全地删除它们,甚至无法安全地读取它们.

    通过合理安排语句,可以实现异常安全的代码.代码实现如下:

    1 Widget& Widget::operator=(const Widget& rhs)
    2 {
    3     Bitmap* pOrig = pb;
    4     pb = new Bitmap(*rhs.pb);
    5     delete pOrig;
    6     return *this;
    7 }

    如果"new Bitmap"抛出异常,pb会保持原状.

    即使没有证测试,上述代码还是能够处理自我赋值.

    此外,还有一种方法copy and swap技术可以实现operator=函数的异常安全和自我赋值安全.代码实现如下:

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

    上述代码中,第3行代码创建临时变量temp,作为rhs数据的一份复件.

    由于swap函数会交换*this和参数对象的数据,如果直接将rhs作为参数,则会改变rhs对象的值,与operator=的操作不符.

    我们可以将operator=函数声明为"以by value方式接受实参",这样可减少临时变量temp的创建

    将"copying动作"从函数本体移至"函数参数构造阶段".代码如下:

    1 Widget& Widget::operator=(Widget rhs)    //pass by value,rhs是被传对象的一份复件
    2 {
    3     swap(this);                //将*this的数据和复件的数据互换
    4     return *this;
    5 }
  • 相关阅读:
    Android——ListView学习笔记(一)
    记录笔记——关于request.getRequestDispatcher().forward(request, response)的跳转问题
    Python + openCV 实现图像垂直投影和水平投影
    2020年-第三周助教总结-第二组
    Python记录——字符串的常用方法
    2020年-第二周助教总结-第二组
    Android开发——三种活动跳转方式
    2020年-第一周助教总结-第二组
    Python —— 实例化ndarray对象
    海信聚好看矫恒浩:构建异地双活混合云,利用公共云应对流量突增
  • 原文地址:https://www.cnblogs.com/dwdxdy/p/2595821.html
Copyright © 2011-2022 走看看