C Primer學習筆記 13 拷貝控制

2021-06-16 05:09:25 字數 2449 閱讀 8854

題記:本系列學習筆記(c++ primer學習筆記)主要目的是討論一些容易被大家忽略或者容易形成錯誤認識的內容。只適合於有了一定的c++基礎的讀者(至少學完一本c++教程)。

如果文中有錯誤或遺漏之處,敬請指出,謝謝!

c++類中有四個不可或缺的部分,那就是建構函式、拷貝建構函式、賦值操作符和析構函式。如果類中沒有定義這些函式,那麼編譯器將為類自動生成這些函式。當然,你也可以通過private控制策略限定不使用拷貝建構函式和賦值操作符。

其中,拷貝建構函式、賦值操作符和析構函式總稱為拷貝控制(copy control)。

當類中有指標類資料成員時,一般都需要自已實現類的拷貝控制。通常有兩種處理策略:一是定義值型類,每個類保留乙份指標指向的物件的拷貝;另一種更常用的策略是使用智慧型指標(smart pointer),其通用技術是採用引用計數(reference count)來實現共享指標指向的物件。

拷貝建構函式

我們知道c++中變數初始化有兩種形式:直接初始化和拷貝初始化。直接初始化將初始化放在圓括號中,而拷貝初始化使用=符號。對於內建型別,這兩者基本上沒有區別。但對於類型別,兩種方式是有區別的:直接初始化直接呼叫與實參匹配的建構函式;而拷貝初始化總是呼叫拷貝建構函式,具體而言,就是拷貝初始化首先使用指定建構函式建立乙個臨時物件,然後用拷貝建構函式將那個臨時物件拷貝到正在建立的物件。

支援拷貝初始化主要是為了與c的用法相容。當情況允許時,可以允許編譯器跳過拷貝建構函式直接建立物件,但編譯器沒有義務這樣做。注:事實上大多數編譯器都跳過了拷貝建構函式,因為這完全可以跳過,比如在vc6.0和mingw2.05。

我們知道可以用表示容量的單個引數來初始化容器,容器的這種構造方式使用了預設建構函式和拷貝建構函式。例如:

vectorsvec(5);

編譯器首先使用string的預設建構函式建立乙個臨時值來初始化svec,然後使用拷貝建構函式將臨時物件拷貝到svec的每個元素。示例**如下:

#

include

<

iostream

>

#include

<

vector

>

using

namespace

std;

class

test

test

(const

test

& t)};

int main(

)

輸出結果為:(mingw 2.05和vc6.0)

contructor

copy contructor

copy contructor

copy contructor

copy contructor

copy contructor

對於元素為類型別的陣列,可以使用陣列初始化列表來提供顯示元素初始化。此時,使用拷貝初始化來初始化每個元素。根據指定值建立適當型別的元素,然後用拷貝建構函式將該值拷貝到相應元素。當然,同前面一樣,是否跳過拷貝建構函式取決於編譯器(事實上,大多數編譯器跳過了這步)。

拷貝建構函式的形參是乙個類型別引用(否則,引數本身就需要過拷貝建構函式了),但一般情況下,我們使用const修飾。並且,一般不應該設定為explicit。

有時需要禁止拷貝類,例如,iostream類就不允許拷貝。這時,應當顯示宣告拷貝建構函式為private,此時可以不定義該函式。若宣告為private且進行了函式定義,則類的友元和成員仍然可以進行拷貝。

注意:宣告而不定義成員函式是合法的,但是,使用未定義成員的任何嘗試將導致鏈結失敗。

合成的拷貝建構函式

如果我們沒有定義拷貝建構函式,則編譯器會自動生成乙個,把這個自動生成的拷貝建構函式叫合成的拷貝建構函式(synthesized copy constructor)。合成的拷貝建構函式執行逐個成員初始化,將新物件初始化為原物件的副本。如果成員是內建型別,則執行位拷貝;如果成員是類型別,則呼叫相應的拷貝建構函式;如果成員是陣列型別,則分別對每個陣列元素進製拷貝。

賦值操作符

賦值操作符的右運算元一般以const引用傳遞,為了與內建型別的行為一致,常返回該類型別的引用。通常,拷貝建構函式和賦值操作符是同時出現的,定義了乙個就應當定義另乙個。

賦值操作符乙個必須小心的地方時檢查自賦值。

析構函式

三法則(rule of three):如果類需要自定義析構函式,則它往往也需要拷貝建構函式和賦值操作符。

合成的析構函式按成員在類中宣告次序的逆序來撤銷成員。

析構函式與拷貝建構函式或者賦值操作符之間的乙個重要區別是:即使我們編寫了自己的析構函式,在自定義析構函式執行結束後,合成析構函式仍然將繼續執行,它來完成成員資料的撤銷工作。

如果文中有錯誤或遺漏之處,敬請指出,謝謝!

[1] c++ primer(edition 4)

[2] thinking in c++(volume two, edition 2)

[3] international standard:iso/iec 14882:1998

c primer 學習筆記13 模板

書本583頁 16.6接受乙個陣列實參的標準庫函式begin和end是如何工作的 templateconst t my begin const t a n template const t my end const t a n 16.7編寫乙個constexpr模板,返回給定陣列的大小 includ...

C Primer筆記 13 複製控制

當定義乙個新型別的時候,需要顯式或隱式地指定複製 賦值和撤銷該型別的物件時會發生什麼 這就是通過定義特殊成員 複製建構函式 賦值操作符和析構函式來達到的。如果沒有顯式定義複製建構函式或賦值操作符,編譯器會為我們定義。複製建構函式 賦值操作符和析構函式總稱為複製控制 copy constrol 編譯器...

C 學習筆記之 13 拷貝控制

本文將學習類如何通過一組函式控制物件拷貝 賦值 移動和銷毀,這組函式分別是拷貝建構函式 移動建構函式 拷貝賦值運算子 移動賦值運算子以及析構函式。若類沒有顯示定義這些拷貝控制成員,則編譯器會自動定義。如果乙個建構函式的第乙個引數是自身類型別的引用 幾乎總為const引用 且任何額外引數都有預設值,則...