zoukankan      html  css  js  c++  java
  • Effective C++ 笔记 —— Item 11: Handle assignment to self in operator=.

    An assignment to self occurs when an object is assigned to itself:

    class Widget { ... };
    Widget w;
    //...
    w = w; // assignment to self

    If you try to manage resources yourself, however (which you’d certainly have to do if you were writing a resourcemanaging class), you can fall into the trap of accidentally releasing a resource before you’re done using it.

    class Bitmap { //... };
    class Widget {
        //...
    private:
        Bitmap *pb; // ptr to a heap-allocated object
    };
    
    
    Widget& Widget::operator=(const Widget& rhs) // unsafe impl. of operator=
    {
        delete pb; // stop using current bitmap
        pb = new Bitmap(*rhs.pb); // start using a copy of rhs’s bitmap
        return *this; // see Item 10
    }

    The self-assignment problem here is that inside operator=, *this (the target of the assignment) and rhs could be the same object. When they are, the delete not only destroys the bitmap for the current object, it destroys the bitmap for rhs, too. At the end of the function, the Widget — which should not have been changed by the assignment to self — finds itself holding a pointer to a deleted object!

    The traditional way to prevent this error is to check for assignment to self via an identity test at the top of operator=:

    Widget& Widget::operator=(const Widget& rhs)
    {
        if (this == &rhs) return *this; // identity test: if a self-assignment,
        // do nothing
        delete pb;
        pb = new Bitmap(*rhs.pb);
        return *this;
    }

    This works, but it was also exception-unsafe, and this version continues to have exception trouble.

    Happily, making operator= exception-safe typically renders it selfassignment-safe, too. 

    For example, we just have to be careful not to delete pb until after we’ve copied what it points to:

    Widget& Widget::operator=(const Widget& rhs)
    {
        Bitmap *pOrig = pb; // remember original pb
        pb = new Bitmap(*rhs.pb); // point pb to a copy of rhs’s bitmap
        delete pOrig; // delete the original pb
        return *this;
    }

    If we take advantage of the facts:

    • a class’s copy assignment operator may be declared to take its argument by value.
    • passing something by value makes a copy of it.
    class Widget {
        //...
        void swap(Widget& rhs); // exchange *this’s and rhs’s data; ... // see Item 29 for details
    };
    
    Widget& Widget::operator=(Widget rhs) // rhs is a copy of the object passed in — note pass by val
    { 
        swap(rhs); // swap *this’s data with the copy’s
        return *this;
    }

    This approach sacrifices clarity at the altar of cleverness, but by moving the copying operation from the body of the function to construction of the parameter, it’s a fact that compilers can sometimes generate more efficient code.

    Things to Remember

    • Make sure operator= is well-behaved when an object is assigned to itself. Techniques include comparing addresses of source and target objects, careful statement ordering, and copy-and-swap.
    • Make sure that any function operating on more than one object behaves correctly if two or more of the objects are the same.
  • 相关阅读:
    pyCharm最新2018激活码
    pycharm fiddler requests.exceptions.SSLError
    耐克的毛毛虫
    ROS-RouterOS hAP ac2+usb 4G上网卡+小米新推的无线上网卡是绝配
    TOM带你玩充电 篇三:15款5号电池横评及选购建议——南孚金霸王小米宜家耐时品胜一个都逃不了
    关于DELL服务器如果采购散件,进行服务器升级的相关说明
    开通微信零钱通的方法微信免手续费提现
    近期给朋友推荐的笔记本型号
    江苏中石化加油卡积分的几种类别
    Selenium geckodriver异常
  • 原文地址:https://www.cnblogs.com/zoneofmine/p/15209008.html
Copyright © 2011-2022 走看看