zoukankan      html  css  js  c++  java
  • effective C++ 条款 11:在operator= 处理‘自我赋值’

    假设建立一个class来保存一个指针指向一块儿动态分配的位图(bitmap)

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

    这个operator=实现代码表面看上来合理, 但自我赋值出现时并不安全,也不具备异常安全性。

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

    rhs和*this可能是同一个对象。这样的话delete就不只是销毁当前对象的bitmap,它也销毁rhs的bitmap。

    预阻止这种错误,传统的做法是在operator=的最前面的一个“证同测试”identity test

    Widget& Widget::operator=(const Widget& rhs)
    {//证同测试,如果是自我赋值就不做任何事
        if (this == &rhs)
        {
            return *this;
        }

        delete pb;
        pb = new Bitmap(*rhs.pb);
        return *this;
    }

    还不具备“异常安全性”,如果“new Bitmap”导致异常(不论是因为分配时内存不足,还是因为Bitmap的copy构造函数抛出异常),Widget最终会有一个指针指向一快被删除的Bitmap。

    让operator=具备“异常安全性”往往自动获得“自我赋值安全”的回报。如下代码,只需注意在复制pb所指东西之前别删除pb

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

    这样如果new Bitmap抛出异常,pb 保持原状。即使没有证同测试,还是能够处理自我赋值,只是不是最高效的办法,但他行得通。如果关心效率, 把“证同测试”加上,但是这项测试本身也需要成本,是代码变大,并导入一个新的控制流分支,而且“自我赋值”的发生频率并不高。

    确保代码不但“异常安全”而且“自我赋值安全”的一个替代方案是,使用所谓的copy and swap技术:

    class Widget
    {
    public:
        void swap(Widget& rhs); //交换*this和rhs的数据
    protected:
    private:
        Bitmap* pb;
    };

    Widget& Widget::operator=(const Widget& rhs)
    {
        Widget temp(rhs);
        swap(temp);
        return *this;
    }

    这个主题的另一个变奏曲:1.copy assignment操作符可能被声明为“以by value方式接受实参”;2.以by value方式传递东西会造成一份副本:

    Widget& Widget::operator=(Widget rhs) //pass by value
    {
        swap(rhs);
        return *this;
    }

    确保当对象自我赋值时operator=有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及

    copy and swap

    确定任何函数如果操作一个以上的对象,而其中有多个对象是同一个时,其行为仍然正确

  • 相关阅读:
    【NX二次开发】Block UI 多行字符串
    【NX二次开发】Block UI 字符串
    【NX二次开发】Block UI 枚举
    【NX二次开发】Block UI 切换开关
    Css
    禁止多行文本框textarea拖拽
    HTML5+Css3-webkit-filter
    Google Chrome一些小技巧
    js获取节点
    getAttribute:取得属性; setAttribute:设置属性。
  • 原文地址:https://www.cnblogs.com/lidan/p/2322060.html
Copyright © 2011-2022 走看看