C 中的拷貝控制

2021-07-30 03:30:52 字數 2981 閱讀 6065

當我們定義乙個類時,我們顯式或者隱式的指定了此型別的物件的拷貝、移動、賦值和銷毀時的操作。乙個類通過五種特殊的成員函式來控制這些操作:拷貝建構函式、拷貝賦值運算子、移動建構函式、移動賦值運算子和析構函式。 這些操作統稱為

拷貝控制操作。

拷貝建構函式、移動建構函式:定義了用同型別的另乙個物件來初始化本物件時做什麼。

拷貝賦值運算子、移動賦值運算子:定義將乙個物件賦予同型別的另乙個物件時做什麼。

析構函式:定義當此型別物件銷毀時做什麼。

1)如果乙個建構函式的第乙個引數是自身類型別的引用(

必須),且任何額外引數都是預設值,則此建構函式是拷貝建構函式。

為什麼必須是引用?

如果乙個拷貝建構函式發生呼叫時,使用的不是引用,那麼就會發生形參傳值傳遞的方式。而傳值的方式其實就是拷貝初始化的方式,此時呼叫的該類的拷貝建構函式,而拷貝建構函式又是傳值傳遞,如此迴圈,則造成傳值拷貝無限遞迴,造成呼叫失敗。

2)如果我們沒有為乙個類定義拷貝建構函式,那麼編譯器會自動為我們合成乙個拷貝建構函式。合成的拷貝建構函式會將其引數成員逐個地拷貝到正在建立的物件中。

3)直接初始化時利用函式匹配來匹配最合適的建構函式進行物件的初始化,而拷貝初始化是將右側運算物件拷貝到正在建立的物件中,必要時還會進行型別轉換(應該是先進行型別轉換,然後才進行拷貝)。

發生拷貝初始化的場合有:

a)使用=運算子進行變數定義時(注意此處非賦值);

b)從乙個返回型別為非引用型別的函式返回乙個物件時(函式的返回型別為非引用時,會初始化乙個臨時量);

c)將乙個物件作為實參傳遞給乙個非引用型別的形參時(也就是在函式呼叫時引數傳遞使用的是傳值方式);

d)用花括號列表初始化乙個陣列中或者乙個聚合類中的成員時。

4)如果類未定義自身的拷貝賦值運算子,那麼會進行自動合成,合成拷貝運算子返回乙個指向左側運算物件的引用。

5)過載運算子本質上是函式,函式名由關鍵字operator後接要定義的運算子的符號組成,其引數表示運算子的運算物件,引數型別與所處類的型別相同。過載賦值運算子必須是類的成員,它將其右側運算物件的非static成員依照對應關係賦予運算子左側物件的成員。

6)建構函式有乙個初始化部分和乙個函式體,成員的初始化是在函式體執行之前完成的,並按照在類中出現的順序進行初始化。(需要更多的研究!!!)

7)可以使用 = default 顯式地要求編譯器生成合成的拷貝控制成員。=default 只適用於合成版本的成員函式。

8)可以使用 = delete將 拷貝建構函式和拷貝賦值運算子定義為

刪除函式。刪除函式:雖然進行了宣告但不可以使用。=delete必須出現在函式第一次宣告的時候並可以對任何函式使用 = delete。(

在函式匹配或者繼承中也許也可以發揮作用!)

9)也可以將 拷貝建構函式和拷貝賦值運算子宣告為private成員來阻止拷貝。但這種情況並不會阻止其友元和成員函式對物件進行拷貝。若想讓友元和成員函式的拷貝,可以只宣告但不定義建構函式。(

宣告但不定義乙個成員函式是合法的,但有乙個例外。) 

此時如何來例項化乙個該類型別的物件呢?

10)需要重新定義拷貝建構函式的雷也需壓重新定義過載賦值運算子,反之依然。

1)析構函式執行與建構函式相反的操作:建構函式會初始化物件的非static資料成員和一些其他工作;析構函式釋放物件使用的資源並銷毀非static資料成員。

2)析構函式函式名由波浪線和類名組成,沒有返回值和形參。(

不接受引數)

3)析構函式函式由乙個函式體和析構部分組成,其中析構部分是隱式的;首先執行函式體,然後按照成員初始化順序進行銷毀(

函式體中並不會銷毀成員);內建型別沒有析構函式。(具體的析構順序還需**!!!)

4)析構函式呼叫的場合有:

a)變數在離開其作用域時被銷毀;

b)當乙個物件被銷毀時,其成員被銷毀(物件中可能還有其他帶有析構函式的成員);

c) 容器被銷毀時,其元素被銷毀;

d)動態分配的物件,當對指向它的指標 應用delete運算子時被銷毀;

e)對於臨時物件,當建立它的完整表示式結束時被銷毀。

5)當乙個類未定義自身的析構函式時,編譯器會自動合成乙個析構函式。但

合成的析構函式不會銷毀動態分配的記憶體。

6)需要重新定義析構函式的類也需要重新定義拷貝建構函式和過載賦值運算子。

7)析構函式不能是刪除成員,否則將無法銷毀物件。

1) 右值引用是必須繫結到右值的引用,通過&&(中間沒有空格)來獲得,且

只能繫結將要銷毀的物件。常規的引用可以稱之為

左值引用。左值引用不能繫結右值,但乙個const的左值引用可以繫結右值。左值引用不能繫結到要求轉換的表示式、字面常量、或者返回右值的表示式。

2)左值物件可以持久的保持狀態,而右值物件要麼是字面常量,要麼就是表示式求值過程中建立的臨時物件。變數表示式都是左值。

3)呼叫move函式可以獲得繫結到左值上的右值引用。可以對移後的原物件進行銷毀、或者賦新值,但是不能夠使用(訪問)它。 而且

使用move的時候需要用std::move。

4)移動建構函式不分配任何新記憶體,新物件將接管源物件的記憶體。且移動建構函式的第乙個引數必須為右值引用,任何其他的參是都必須是預設實參。

5)移後源物件必須可以析構。

6)編譯器可以自動合成移動建構函式和移動賦值運算子,但是是有條件的。當乙個類定義了自己的拷貝建構函式和拷貝賦值運算子,編譯器是不會為其合成移動建構函式和移動賦值運算子。因此有些類是不存在移動操作的,而此時會通過函式匹配來使用拷貝操作替代移動操作。只有當乙個類沒有定義自己版本的拷貝操作且其成員均可移動時才會合成移動操作。如果乙個類定義了移動操作,那麼其合成的拷貝操作會被定義成刪除的。

7)移動建構函式通常不會丟擲異常,可以使用noexcept關鍵字來通知編譯器。一般寫在函式呼叫運算子( )之後和成員初始化器之前。

1)如果乙個類定義了自己的swap,那麼通常會使用自己的版本而不是標準庫定義的版本。

1)右值和左值引用成員函式。類似於const函式。規定了函式的返回值是哪種引用型別,位置和const相當。但當同時有const和引用限定符時,const在前引用限定符在後。

2)關於刪除函式。

C 拷貝控制

本文主要討論c 類定義中的拷貝控制 copy control 拷貝建構函式 賦值操作符和析構函式。如果文中有錯誤或遺漏之處,敬請指出,謝謝!c 類中有四個不可或缺的部分,那就是建構函式 拷貝建構函式 賦值操作符和析構函式。如果類中沒有定義這些函式,那麼編譯器將為類自動生成這些函式。當然,你也可以通過...

C 拷貝控制

當定義乙個類時,顯示或隱式地指定了此型別的物件在拷貝 賦值和銷毀時所執行的操作,通過三個特殊的成員函式來控制這些操作,分別是拷貝建構函式,賦值運算子和析構函式。拷貝建構函式定義了當使用同型別的另乙個物件初始化新物件時的操作,賦值運算子定義了將乙個物件賦值給同型別的另乙個物件時的操作,析構函式定義了此...

C 拷貝控制

拷貝建構函式 如果有乙個建構函式第乙個引數是自身類型別的引用,且任何額外引數都有預設值,則此建構函式是拷貝建構函式。class foo 如果沒有為乙個類定義拷貝建構函式,編譯器會為我們定義乙個。拷貝建構函式不僅在我們用 定義變數時發生,也會在一下情況發生 拷貝賦值運算子 與拷貝建構函式一樣,如果類未...