Effective C++(11)自己付与(a=a)の場合どうなりますか?

2199 ワード

問題の焦点:
自己賦課は少し愚かな行為のように見えますが、実はいつも起こります.
まず合法的です
次に、必ずしも安全ではありません.
再び、それは時にはそんなに明らかではありません.
まずデモを見て
class Widget { ... };

Widget w;

...

 /**          **/

w = w;   



/**            **/

//         i = j         

a[i] = a[j]



/**         **/

*px = *py;



/**          “  ” **/

class Base { ... };

class Derived : public Base { ... };

void doSomething( const Base& rb, Derived* pd);     // rb   *pd       

一般的に、ポインタと参照を操作し、同じタイプの複数のオブジェクトを指すために使用されるセグメントコードの場合、これらのオブジェクトが同じかどうかを考慮する必要があります.
自己付与がもたらす可能性のある2つの潜在的な危険:
  • 自己付与セキュリティ
  • 異常安全
  • 次の例を見てみましょう.
    class Bitmap { ... };
    
    class Widget {
    
        ... 
    
    private:
    
        Bitmap* pd;
    
    };
    
    
    
    /** operator=      **/
    
    Widget&
    
    Widget::operator=(const Widget& rhs)
    
    {
    
        delete pb;
    
        pb = new Bitmap(*rhs.pb);
    
        return *this;
    
    }

    自己付与セキュリティ:
    rhsと現在のオブジェクトが同じオブジェクトである場合、現在のオブジェクトのpbを破棄すると、rhsのオブジェクトも破棄されます.
    改善:承認テスト
    /** operator=      **/
    
    Widget&
    
    Widget::operator=(const Widget& rhs)
    
    {
    
        if (this == &rhs) return *this;   //     
    
    
    
        delete pb;
    
        pb = new Bitmap(*rhs.pb);
    
        return *this;
    
    }

    上記の改良されたコードは、自己付与セキュリティの問題を回避します.
    2つ目の問題に注目しましょう
    異常セキュリティ:
    new Bitmap()に異常が発生した場合、その結果、pb付与値が真っ白になり、Widgetは最終的に削除されたBitmapを指すポインタを持つ.
    改善一:文を丹念に手配する
    /** operator=      **/
    
    Widget&
    
    Widget::operator=(const Widget& rhs)
    
    {
    
        Bitmap* pOrig  = pb;
    
        pb = new Bitmap(*rhs.pb);     //   new Bitmap    ,pb    
    
        delete pOrig;
    
        return *this;
    
    }

    改善案2:copy and swap
    class Widget {
    
    ...
    
    void swap(Widget& rhs);
    
    ...
    
    };
    
    
    
    Widget& Widget::operator=(const Wdiget& rhs)
    
    {
    
        Widget temp(rhs);
    
        swap(temp);
    
        return *this;
    
    }

    アイデア:
    コピーコンストラクション関数を「値別転送」と宣言するには
    値で渡すとコピーが作成されます
    まとめ:
    オブジェクトが自己割り当てされているときにoperator=が良好な動作をしていることを確認します.
    次の内容が含まれます.
    オブジェクトソース
    ターゲットオブジェクトアドレス
    文の順序
    任意の関数が1つ以上のオブジェクトを操作し、複数のオブジェクトが同じオブジェクトである場合でも、その動作が正しいことを確認します.
    参考資料:
    《Effective C++ 3rd》