第十三章 拷貝控制

2021-07-02 15:31:49 字數 2090 閱讀 7798

在定義任何 c++ 類時,拷貝控制操作都是必要部分。如果我們不顯示定義這些操作,編譯器也會為我們定義,但編譯器定義的版本的行為可能並非我們所想。

拷貝初始化不僅在我們用=定義變數時會發生,在下列情況下也會發生:

① 將乙個物件作為實參傳遞給乙個非引用型別的形參;

② 從乙個返回型別為非引用型別的函式返回乙個物件;

③ 用花括號列表初始化乙個陣列中的元素或乙個聚合類中的成員。

過載運算子本質上是函式,其名字有 operator 關鍵字後接表示要定義的運算子的符號組成。因此,賦值運算子就是乙個名為 operator= 的函式。

某些運算子,包括賦值運算子,必須定義為成員函式。如果乙個運算子是乙個成員函式,其左側運算物件就繫結到隱式的 this 引數。

在乙個析構函式中,首先執行函式體,然後銷毀成員。成員按照初始化順序的逆序銷毀。

在乙個析構函式中,不存在類似建構函式中初始化列表的東西來控制成員如何銷毀,析構部分是隱式的。銷毀類型別的成員需要執行成員自己的析構函式。內建型別沒有析構函式,因此銷毀內建型別成員什麼也不需要做。

隱式銷毀乙個內建指標的成員不會 delete 它所指向的物件。而智慧型指標是類型別,所以具有析構函式。

如果乙個類需要自定義析構函式,幾乎可以肯定它也需要自定義拷貝賦值運算子和拷貝建構函式。

對於析構函式已刪除的型別,不能定義該型別的變數或釋放指向該型別動態分配物件的指標。

如果乙個類有資料成員不能預設構造、拷貝、複製或銷毀,則對應的成員函式被定義為刪除的。

希望阻止拷貝的類應該使用 =delete 來定義它們自己的拷貝建構函式和拷貝賦值運算子,而不應該將它們宣告為 private 。

當你編寫賦值運算子時,有兩點需要記住:

① 如果將乙個物件賦予它自身,賦值運算子必須能正確工作;

② 大多數賦值運算子組合了析構函式和拷貝建構函式的工作。

(當你編寫乙個賦值運算子時,乙個好的模式是先將右側運算物件拷貝到乙個區域性臨時物件中。)

與拷貝控制成員不同, swap 並不是必要的。但是,對於分配了資源的類,定義 swap 可能是一種很重要的優化手段。

使用拷貝和交換的賦值運算子自動就是異常安全的,且能正確處理自賦值。

返回左值引用的函式,連同賦值、下標、解引用和前置遞增/遞減運算子,都是左值的表示式的例子。返回非引用型別的函式,連同算數、關係、位及後置遞增/遞減運算子,都生成右值。

左值有持久的狀態,而右值要麼是字面常量,要麼是在表示式求值過程中建立的臨時物件。(右值引用所引用的物件將要被銷毀,或者該物件沒有其他使用者)

變數是左值,因此我們不能將乙個右值引用直接繫結到乙個變數上,即使這個變數時右值引用型別也不行。

除非標準庫知道我們的移動建構函式不會丟擲異常,否則它會認為移動我們的類物件時可能會丟擲異常,並且為了處理這種可能性而做一些額外的工作。

不丟擲異常的移動建構函式和移動賦值運算子必須標記為 noexcept 。

除非 vector 知道元素型別的移動建構函式不會丟擲異常,否則在重新分配記憶體的過程中,它就必須使用拷貝建構函式而不是移動建構函式。

在移動操作之後,移後源物件必須保持有效的、可析構狀態,但是使用者不能對其值進行任何假設。

如果乙個類定義了自己的拷貝建構函式、拷貝賦值運算子或析構函式,編譯器就不會為它合成移動建構函式和移動賦值運算子了。

只有當乙個類沒有定義任何自己版本的拷貝控制成員,且它的所有資料成員都能移動構造或移動賦值時,編譯器才會為它合成移動建構函式或移動賦值運算子。

如果移動操作可能被定義為刪除的函式,編譯器就不會合成它們。

定義了乙個移動建構函式或移動賦值運算子的類必須也定義自己的拷貝操作,否則,這麼成員預設地被定義為刪除的。

移動右值,拷貝左值,但如果沒有移動建構函式,右值也被拷貝。(可以將 && 轉換為 const &)

所有五個拷貝控制成員應該看做乙個整體:一般來說,如果乙個類定義了任何乙個拷貝控制操作,它就應該定義所有五個操作。

除了建構函式和賦值運算子外,如果乙個成員函式同事提供拷貝和移動版本,它也能從中受益。

對於 & 限定的函式,我們只能將它用於左值;對於 && 限定的函式,只能用於右值。

如果乙個成員函式有引用限定符,則具有相同引數列表的所有版本都必須有引用限定符。

呼叫 move 隱含地承諾我們將不會再使用移後源物件,除了銷毀它或賦予它乙個新值之外。

第十三章 拷貝控制

如果乙個建構函式第乙個引數是自身類型別的引用,且任何額外引數都有預設值,則為拷貝建構函式 拷貝初始化發生情況 拷貝建構函式自己的引數必須是引用型別否則會遞迴死迴圈 拷貝賦值運算子是乙個名為 operator 的函式 建構函式初始化物件的非static資料成員 析構函式釋放物件使用的資源,並銷毀物件的...

第十三章 拷貝控制

拷貝控制操作 copy control 合成拷貝賦值運算子 合成析構函式 賦值運算子組合了析構函式和拷貝建構函式的工作,先在底層生成物件空間,刪除類內原有的記憶體空間,然後指向新分配的指標。hasptr operator const hasptr hp move函式 移動賦值運算子 合成的移動操作 ...

第十三章筆記 拷貝控制

乙個類通過定義五種特殊的成員函式來控制這些操作,包括 拷貝建構函式 copy construcor 拷貝賦值運算子 copy assignment operator 移動建構函式 move constructor 移動賦值運算子 move assignment operator 和析構函式 dest...