zoukankan      html  css  js  c++  java
  • 《Effective C++ 》学习笔记——条款11

    ***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************



    二、Constructors,Destructors and Assignment Operators


    Rule 11:Handle assignment to self in operator =

    规则11:在 operator= 中处理“自我赋值”



    1.自我赋值?!

    比方这种:

    class Widget  {  ...  };
    Widget w;
    ...
    w = w;    // 赋值给自己

    这样做是同意的,所以不要期盼不会发生,由于鸟大了,什么林子都有 o(╯□╰)o。。


    2.自我赋值 其它形式

    ① 除了最直观的   w=w

    ② 另一些隐蔽的,比方:

    a[i] = a[j]; // 万一 i等于j

    ③ *px = *py 

    也许。这两个指针都指向同一个对象

    ④ 还有 base class 与 derived class的:(由于一个基类的引用或者指针。能够指向派生类对象)

    class Base  {  ...  };
    class Derived : public Base  {  ...  };
    void doSomething( const Base& rb , Derived* pd);<span style="white-space:pre">	</span>// rb 和 pd 可能指向同一个对象


    总结下来就是,假设某段代码操作pointers 或 references,而它们被用来“指向多个同样类型的对象”,就须要考虑这些对象是否为同一个,并且假设对象来自同一个继承体系。它们甚至不须要声明为同类型就可能造成“别名”(如上面的④)。



    3.愚蠢的自我赋值,会导致?

    class Bitmap  {  ...  };
    class Widget  {
        ...
    private:
        Bitmap* pb;
    };
    
    Widget& Widget::operator=( const Widget& rhs )<span style="white-space:pre">		</span>// 一分不安全的 operator= 实现版本号
    {
        delete pb;<span style="white-space:pre">						</span>// 停止使用当前的 Bitmap
        pb = new Bitmap(*rhs.pb);<span style="white-space:pre">				</span>// 使用 rhs's的Bitmap 副本
        return *this;<span style="white-space:pre">					</span>// 这个问题在上一个条款(条款10)中介绍过
    }

    这个样例说明了虾米呢?

    就是,假设是

    a = b;

    工作原理是。先把a的版本号删除。然后在将b赋值给a。

    所以,假设a与b 是同一个东西,它就会导致错误,

    按上面的样例来讲,就是,删除pb的同一时候。rhs也被删除了,所以第二行的赋值动作就会指向一个已经被删除的对象。



    4.看到错误了,总归要解决的

    有三种解决方式

    <1> 第一种方案——“证同測试” identity test

    Widget& Widget::operator=(const Widget& rhs )
    {
        if( this == &rhs )    return *this;<span style="white-space:pre">		</span>// identity test
        
        delete pb;
        pb = new Bitmap(*rhs.pb);
        return *this;
    }
    就是在运行代码前。先推断是否是同一个东西,若是,就不须要做不论什么事情。直接返回。


    <2> 另外一种方案——先赋值,再删除

    Widget& Widget::operator=(const Widget& rhs)
    {
        Bitmap* pOrig = pb;<span style="white-space:pre">			</span>// 先备份
        pb = new Bitmap(*rhs.pb);<span style="white-space:pre">		</span>// 赋值
        delete pOrig;<span style="white-space:pre">			</span>// 删除备份
        return *this;
    }
    就是仅仅须要注意在复制之前别删除原来的,先备份一下。

    这也许不是处理“自我赋值”最高效的办法。但它行得通。


    <3> 第三种方案——copy and swap

    class Widget  {
        ...
        void swap( Widget& rhs );<span style="white-space:pre">				</span>// 交换*this和rhs的数据,在后面条款29会有具体解释
        ...
    };
    Widget& Widget::operator=( const Widget& rhs )
    {
        Widget temp(rhs);<span style="white-space:pre">					</span>// 为rhs数据制作一份复件
        swap(temp);
        return *this;
    }

    并且,还有还有一种形式。对于:①某class的 copy assignment操作符声明为“以 by value 方式接受实參”。②以by value方式 传递东西会造成一份复件:

    Widget& Widget::operator= ( Widget rhs )<span style="white-space:pre">	</span>// rhs是被传递对象的一份复件
    {<span style="white-space:pre">		</span>
        swap(rhs);<span style="white-space:pre">					</span>// 注意这里是 pass by value
        return *this;<span style="white-space:pre">				</span>// 将*this的数据和复件的数据互换
    }

    而这样的做法也是作者比較不推荐的。由于它为了 伶俐巧妙的修补 牺牲了 代码的清晰性。可读性略低。

    但 将 copying 动作 从函数本体 移至 函数參数构造阶段 却能够 让编译器产生更高效的代码。



    5.请记住

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

    ★ 确定不论什么函数假设操作一个以上的对象,而当中多个对象是同一个对象时,其行为仍然正确。



    ***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************


  • 相关阅读:
    Android AsyncTask
    android 自定义 view 和 ViewGroup
    Android Acitivity 生命周期
    Android Service 与 IntentService
    Android LocalBroadcastManager 与 BroadcastReceiver
    如何提升 service 等级,不被kill(整合)
    Android 插件开发,做成动态加载
    新提交审核app保留检查更新入口将被拒绝(读取App Store 版本号的)
    Android: Service中创建窗口显示
    如何升级PowerShell
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5240200.html
Copyright © 2011-2022 走看看