<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # Item 11: 在 operator= 中處理 assignment to self(自賦值) 作者:Scott Meyers 譯者:fatalerror99 (iTePub's Nirvana) 發布:http://blog.csdn.net/fatalerror99/ 當一個 object(對象)賦值給自己的時候就發生了一次 assignment to self(自賦值): ``` class Widget { ... }; Widget w; ... w = w; // assignment to self ``` 這看起來很愚蠢,但它是合法的,所以應該確信客戶會這樣做。另外,assignment(賦值)也并不總是那么容易辨別。例如, ``` a = a[j]; // potential assignment to self ``` 如果 i 和 j 有同樣的值就是一個 assignment to self(自賦值),還有 ``` *px = *py; // potential assignment to self ``` 如果 px 和 py 碰巧指向同一個東西,這也是一個 assignment to self(自賦值)。這些不太明顯的 assignments to self(自賦值)是由 aliasing(別名)(有不止一個方法引用一個 object(對象))造成的。通常,使用 references(引用)或者 pointers(指針)操作相同類型的多個 objects(對象)的代碼需要考慮那些 objects(對象)可能相同的情況。實際上,如果兩個 objects(對象)來自同一個 hierarchy(繼承體系),甚至不需要公開聲明,它們就是相同類型的,因為一個 base class(基類)的 reference(引用)或者 pointer(指針)也能夠引向或者指向一個 derived class(派生類)類型的 object(對象): ``` class Base { ... }; class Derived: public Base { ... }; void doSomething(const Base& rb, // rb and *pd might actually be Derived* pd); // the same object ``` 如果你遵循 Item 13 和 14 的建議,你應該總是使用 objects(對象)來管理 resources(資源),而且你應該確保那些 resource-managing objects(資源管理對象)被拷貝時行為良好。在這種情況下,你的 assignment operators(賦值運算符)在你沒有考慮自賦值的時候可能也是 self-assignment-safe(自賦值安全)的。然而,如果你試圖自己管理 resources(資源)(如果你正在寫一個 resource-managing class(資源管理類),你當然必須這樣做),你可能會落入在你用完一個 resource(資源)之前就已意外地將它釋放的陷阱。例如,假設你創建了一個 class(類),它持有一個指向動態分配 bitmap(位圖)的 raw pointer(裸指針): ``` class Bitmap { ... }; class Widget { ... private: Bitmap *pb; // ptr to a heap-allocated object }; ``` 下面是一個表面上看似合理 operator= 的實現,但如果出現 assignment to self(自賦值)則是不安全的。(它也不是 exception-safe(異常安全)的,但我們要過一會兒才會涉及到它。) ``` Widget& Widget::operator=(const Widget& rhs) // unsafe impl. of operator= { delete pb; // stop using current bitmap pb = new Bitmap(*rhs.pb); // start using a copy of rhs's bitmap return *this; // see Item 10 } ``` 這里的 self-assignment(自賦值)問題在 operator= 的內部,*this(賦值的目標)和 rhs 可能是同一個 object(對象)。如果它們是,則那個 delete 不僅會銷毀 current object(當前對象)的 bitmap(位圖),也會銷毀 rhs 的 bitmap(位圖)。在函數的結尾,Widget——通過 assignment to self(自賦值)應該沒有變化——發現自己持有一個指向已刪除 object(對象)的指針。 防止這個錯誤的傳統方法是在 operator= 的開始處通過 identity test(一致性檢測)來阻止 assignment to self(自賦值): ``` Widget& Widget::operator=(const Widget& rhs) { if (this == &rhs) return *this; // identity test: if a self-assignment, // do nothing delete pb; pb = new Bitmap(*rhs.pb); return *this; } ``` 這個也能工作,但是我在前面提及那個 operator= 的早先版本不僅僅是 self-assignment-unsafe(自賦值不安全)的,它也是 exception-unsafe(異常不安全)的,而且這個版本還有異常上的麻煩。詳細地說,如果 "new Bitmap" 表達式引發一個 exception(異常)(可能因為供分配的內存不足或者因為 Bitmap 的 copy constructor(拷貝構造函數)拋出一個異常),Widget 將以持有一個指向被刪除的 Bitmap 的指針而告終。這樣的指針是有毒的,你不能安全地刪除它們。你甚至不能安全地讀取它們。你對它們唯一能做的安全的事情大概就是花費大量的調試精力來斷定它們起因于哪里。 幸虧,使 operator= exception-safe(異常安全)一般也同時彌補了它的 self-assignment-safe(自賦值安全)。這就導致了更加通用的處理 self-assignment(自賦值)問題的方法就是忽略它,而將焦點集中于達到 exception safety(異常安全)。Item 29 更加深入地探討了 exception safety(異常安全),但是在本 Item 中,已經足以看出,在很多情況下,仔細地調整一下語句的順序就可以得到 exception-safe(異常安全)(同時也是 self-assignment-safe(自賦值安全))的代碼。例如,在這里,我們只要注意不要刪除 pb,直到我們拷貝了它所指向的目標之后: ``` 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; } ``` 現在,如果 "new Bitmap" 拋出一個 exception(異常),pb(以及它所在的 Widget)的遺跡沒有被改變。甚至不需要 identity test(一致性檢測),這里的代碼也能處理 assignment to self(自賦值),因為我們做了一個原始 bitmap(位圖)的拷貝,刪除原始 bitmap(位圖),然后指向我們作成的拷貝。這可能不是處理 self-assignment(自賦值)的最有效率的做法,但它能夠工作。 如果你關心效率,你可以在函數開始處恢復 identity test(一致性檢測)。然而,在這樣做之前,先問一下自己,你認為 self-assignments(自賦值)發生的頻率是多少,因為這個檢測不是免費午餐。它將使代碼(源代碼和目標代碼)有少量增大,而且它將在控制流中引入一個分支,這兩點都會降低運行速度。例如,instruction prefetching(指令預讀),caching(緩存)和 pipelining(流水線操作)的效力都將被降低。 另一個可選的手動排列 operator= 中語句順序以確保實現是 exception- and self-assignment-safe(異常和自賦值安全)的方法是使用被稱為 "copy and swap" 的技術。這一技術和 exception safety(異常安全)關系密切,所以將在 Item 29 中描述。然而,這是一個寫 operator= 的足夠通用的方法,值得一看,這樣一個實現看起來通常就像下面這樣: ``` class Widget { ... void swap(Widget& rhs); // exchange *this's and rhs's data; ... // see Item 29 for details }; Widget& Widget::operator=(const Widget& rhs) { Widget temp(rhs); // make a copy of rhs's data swap(temp); // swap *this's data with the copy's return *this; } ``` 在這個主題上的一個變種利用了如下事實:(1)一個 clsaa(類)的 copy assignment(拷貝賦值運算符)可以被聲明為 take its argument by value(以傳值方式取得它的參數);(2)通過傳值方式傳遞某些東西以做出它的一個 copy(拷貝)(參見 Item 20): ``` Widget& Widget::operator=(Widget rhs) // rhs is a copy of the object { // passed in — note pass by val swap(rhs); // swap *this's data with // the copy's return *this; } ``` 對我個人來說,我擔心這個方法在靈活的祭壇上犧牲了清晰度,但是通過將拷貝操作從函數體中轉移到參數的構造中,有時能使編譯器產生更有效率的代碼倒也是事實。 Things to Remember * 當一個 object(對象)被賦值給自己的時候,確保 operator= 是行為良好的。技巧包括比較 source(源)和 target objects(目標對象)的地址,關注語句順序,和 copy-and-swap。 * 如果兩個或更多 objects(對象)相同,確保任何操作多于一個 object(對象)的函數行為正確。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看