1. 程式人生 > 實用技巧 >C++ 自賦值

C++ 自賦值

https://harttle.land/2015/07/30/effective-cpp-11.html,這個講的很不錯!

1.存在的問題

因為cpp中有指標和引用,它們可以指向同一個變數,所以會存在自賦值的問題。

a[i] = a[j];     //@ 如果i和j有同樣的值,這裡就是一次自賦值
*px = *py;        //@ 如果px和py指向相同的東西,這裡就是一次自賦值 

自賦值一般存在:自賦值安全和異常安全,兩個問題,例如:

自賦值安全

Widget& Widget::operator=(const Widget& rhs){
    delete pb;                   //
stop using current bitmap pb = new Bitmap(*rhs.pb); // start using a copy of rhs's bitmap return *this; // see Item 10 }

當是自賦值的時候,pb已經先被刪除了,那麼後面的new就會為空,這是未知的計算。

異常安全

Widget& Widget::operator=(const Widget& rhs){
    if (this == &rhs) return *this;
    delete pb;                   //
stop using current bitmap pb = new Bitmap(*rhs.pb); // start using a copy of rhs's bitmap return *this; // see Item 10 }

這個自賦值安全,但是沒有異常安全,如果new處出現了異常,那麼pb仍舊指向空。

2.解決辦法

通過調整語句順序

Widget& Widget::operator=(const Widget& rhs){
    Bitmap *pOrig = pb;               // remember original pb
pb = new Bitmap(*rhs.pb); // make pb point to a copy of *pb delete pOrig; // delete the original pb return *this; }

通過一箇中間變數來實現,而沒有使用if的判斷,因為可能會影響效率。

其實也可以這樣:

    HasPtr & operator=(const HasPtr& hp){
        std::string * t=new std::string(*hp.ps);
        delete ps;
        ps=t;
        i=hp.i;
        return *this;
    }

主要就是申請一個臨時變數來指向原來的空間或者是新申請的空間。//delete應該是不會出現異常的吧。

通過swap,賦值和交換

Widget& Widget::operator=(Widget rhs){
    swap(rhs);                // swap *this's data with
    return *this;             // the copy's
}

注意引數為值拷貝,在cpp459頁有講解,

總結:

  1. 判斷兩個地址是否相同
  2. 仔細地排列語句順序
  3. Copy and Swap

自賦值存在的知識點差不多這些。