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 }
  • 相关阅读:
    Linux常用命令-centos
    USACO 2006 Open, Problem. The Country Fair 动态规划
    USACO 2007 March Contest, Silver Problem 1. Cow Traffic
    USACO 2007 December Contest, Silver Problem 2. Building Roads Kruskal最小生成树算法
    USACO 2015 February Contest, Silver Problem 3. Superbull Prim最小生成树算法
    LG-P2804 神秘数字/LG-P1196 火柴排队 归并排序, 逆序对
    数据结构 并查集
    浴谷国庆集训 对拍
    1999 NOIP 回文数
    2010 NOIP 普及组 第3题 导弹拦截
  • 原文地址:https://www.cnblogs.com/dwdxdy/p/2595821.html
Copyright © 2011-2022 走看看