C Primer 第十三章 拷貝控制

2022-02-10 04:38:39 字數 1387 閱讀 5720

當定義乙個類時,我們顯式或隱式指定在此型別的物件執行拷貝,移動,賦值,銷毀時做什麼,通過拷貝建構函式,拷貝賦值運算子,移動建構函式,移動賦值運算子和析構函式。

拷貝賦值與銷毀

如果建構函式的第乙個引數是自身類型別的引用,並且其他引數都有預設值,則此建構函式是拷貝建構函式。第乙個引數一定是引用型別,並且一般為const型別。

直接初始化物件時,我們使用最匹配引數的建構函式初始化物件,拷貝初始化時(賦值的形式)會使用拷貝建構函式初始化物件。通常拷貝初始化由拷貝建構函式來完成,但如果乙個類有移動建構函式,則使用移動建構函式執行拷貝初始化。用等號(=)定義變數時,將乙個物件作為實參傳遞給乙個非引用型別的形參,從函式返回乙個非引用型別的物件,用花括號初始化陣列元素或聚合類中的成員時,這些情況會執行拷貝初始化。

賦值運算子就是乙個名為operator=的函式,賦值運算子返回乙個指向其左側運算物件的引用。如果未定義自己的拷貝賦值運算子,編譯器會合成乙個拷貝賦值運算子。

析構函式與建構函式執行相反的操作,析構函式沒有返回型別也不接受任何引數。析構函式不能過載,對於乙個給定類,只能有乙個析構函式。析構函式首先執行函式體,然後銷毀成員,析構是隱式執行的,銷毀內建指標型別的成員時不會delete所指向的物件。當指向乙個物件的引用或指標離開作用域時,析構函式不會執行。

如果乙個類需要乙個析構函式,幾乎可以肯定該類也需要乙個拷貝建構函式和拷貝賦值運算子。需要拷貝操作的類也需要拷貝賦值操作,需要拷貝賦值運算子的類也一定需要拷貝建構函式,但不一定需要析構函式。注意這裡所說的需要是只自定義。

可以通過將拷貝控制成員宣告為=default來顯示要求編譯器生成合成的版本。

通過在函式後面新增=delete來定義刪除的函式,宣告刪除的函式將阻止對該函式的使用。析構函式不能是刪除的,否則將無法銷毀該物件,可以動態分配乙個有刪除的析構函式的物件,但是不能delete該物件。

合成的拷貝控制成員可能是刪除的,如果類的某個成員含有刪除的拷貝控制成員或析構函式,則該類的合成拷貝控制也將是刪除的。

對於具有引用成員或const成員的型別,編譯器不會為其合成建構函式,如果乙個類有const成員,則不能使用合成的拷貝賦值運算子。對於有引用成員的類,合成拷貝賦值運算子被定義為刪除的。本質上,當不能銷毀拷貝賦值類的成員時,合成的拷貝控制成員就被定義為刪除的。

宣告但不定義乙個成員函式是合法的,訪問乙個未定義的成員將導致鏈結時錯誤。

拷貝控制和資源管理

通常管理類外資源的類需要定義拷貝控制成員。

對於賦值運算子來說,即使將乙個物件賦予它自身也應該能正常工作,好的方法是在銷毀左側運算物件之前拷貝右側運算物件。賦值運算子組合了析構函式和拷貝建構函式的功能。

交換操作

如果乙個類定義了自己的swap函式,演算法將使用自定義函式,否則使用標準庫swap版本。swap並不是必要的,但是使用了資源的類定義swap將是一種重要的優化手段。

拷貝控制示例

第十三章 拷貝控制

在定義任何 c 類時,拷貝控制操作都是必要部分。如果我們不顯示定義這些操作,編譯器也會為我們定義,但編譯器定義的版本的行為可能並非我們所想。拷貝初始化不僅在我們用 定義變數時會發生,在下列情況下也會發生 將乙個物件作為實參傳遞給乙個非引用型別的形參 從乙個返回型別為非引用型別的函式返回乙個物件 用花...

第十三章 拷貝控制

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

第十三章 拷貝控制

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