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

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

  • 相关阅读:
    zabbix基于docker安装
    配置Windows实例NTP服务
    linux 上使用yum 安装openjdk1.8
    【Spring Boot-技巧】API返回值去除为NULL的字段
    【微服务】之七:轻松搞定SpringCloud微服务-API权限控制
    【微服务】之六:轻松搞定SpringCloud微服务-API网关zuul
    【DevOps】团队敏捷开发系列--开山篇
    【微服务】之五:轻松搞定SpringCloud微服务-调用远程组件Feign
    【微服务】之四:轻松搞定SpringCloud微服务-负载均衡Ribbon
    【微服务】之三:从零开始,轻松搞定SpringCloud微服务-配置中心
  • 原文地址:https://www.cnblogs.com/lidan/p/2322060.html
Copyright © 2011-2022 走看看