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********************************************


  • 相关阅读:
    python note 30 断点续传
    python note 29 线程创建
    python note 28 socketserver
    python note 27 粘包
    python note 26 socket
    python note 25 约束
    Sed 用法
    python note 24 反射
    python note 23 组合
    python note 22 面向对象成员
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5240200.html
Copyright © 2011-2022 走看看