命名空間
變體
動作

複製建構函式

出自 cppreference.com
< cpp‎ | language
 
 
C++ 語言
一般主題
流程控制
條件執行陳述式
if
疊代陳述式 (迴圈)
for
範圍 for (C++11)
跳躍陳述式
函式
函式宣告
Lambda 函式運算式
inline 指定符
動態例外規範 (直到 C++17*)
noexcept 指定符 (C++11)
例外
命名空間
型別
指定符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期指定符
初始化
 
 

複製建構函式(copy constructor)是一種建構函式,它可以用相同類別類型的參數來呼叫,並在不變動該參數的情況下,複製該參數的內容。

目錄

[編輯] 語法

class-name (parameter-list ); (1)
class-name (parameter-list ) function-body (2)
class-name (single-parameter-list ) = default; (3) (C++11 起)
class-name (parameter-list ) = delete; (4) (C++11 起)
class-name ::class-name (parameter-list ) function-body (5)
class-name ::class-name (single-parameter-list ) = default; (6) (C++11 起)
class-name - 正在宣告其複製建構函式的類別
參數列表 - 一個非空的參數列表,滿足下列所有條件
  • 若類別類型為 T,則第一個參數的類型為 T&const T&volatile T&const volatile T&,且
  • 沒有其他參數,或者所有其他參數都有預設參數
單參數列表(single-parameter-list) - 一個僅包含一個參數的參數列表,該參數類型為 T&const T&volatile T&const volatile T&,且沒有預設參數
function-body - 複製建構函式的函式主體

[編輯] 說明

1) 在類別定義內宣告複製建構函式。
2-4) 在類別定義內定義複製建構函式。
3) 顯式預設(explicitly-defaulted)的複製建構函式。
4) 刪除的(deleted)複製建構函式。
5,6) 在類別定義外定義複製建構函式(類別必須包含宣告 (1))。
6) 顯式預設的複製建構函式。
struct X
{
    X(X& other); // copy constructor
//  X(X other);  // Error: incorrect parameter type
};
 
union Y
{
    Y(Y& other, int num = 1); // copy constructor with multiple parameters
//  Y(Y& other, int num);     // Error: `num` has no default argument
};

每當從相同類型的另一個物件初始化(透過直接初始化複製初始化)一個物件時,就會呼叫複製建構函式(除非多載解析選擇了更好的匹配,或者該呼叫被省略),這包括:

  • 初始化:T a = b;T a(b);,其中 b 的類型為 T
  • 函式參數傳遞:f(a);,其中 a 的類型為 T,且 fvoid f(T t)
  • 函式回傳:在諸如 T f() 的函式內執行 return a;,其中 a 的類型為 T,且該類型沒有移動建構函式

[編輯] 隱式宣告的複製建構函式

若類別類型沒有提供使用者定義的複製建構函式,編譯器將始終宣告一個非顯式(explicit)inline public 成員作為該類別的複製建構函式。若滿足以下所有條件,此隱式宣告的複製建構函式形式為 T::T(const T&)

  • T 的每個直接基底類別與虛擬基底類別 B 都有一個複製建構函式,其參數類型為 const B&const volatile B&
  • T 的每個類別類型(或類別類型陣列)的非靜態資料成員 M 都有一個複製建構函式,其參數類型為 const M&const volatile M&

否則,隱式宣告的複製建構函式為 T::T(T&)

由於這些規則,隱式宣告的複製建構函式無法繫結至 volatile 左值參數。

一個類別可以擁有多個複製建構函式,例如同時擁有 T::T(const T&)T::T(T&)

即使存在某些使用者定義的複製建構函式,使用者仍可使用關鍵字 default 強制宣告隱式複製建構函式。

(C++11 起)

隱式宣告(或在其首次宣告時預設)的複製建構函式具有異常規格,如 動態異常規格(C++17 前)noexcept 規格(C++17 起) 所述。

[編輯] 隱式定義的複製建構函式

若隱式宣告的複製建構函式未被刪除,則若它被 ODR 使用(odr-used)或為常數評估所需(C++11 起),編譯器會定義它(即產生並編譯函式主體)。對於聯集(union)類型,隱式定義的複製建構函式會複製物件表示(如 std::memmove)。對於非聯集的類別類型,建構函式會按照初始化順序,使用直接初始化對物件的直接基底子物件和成員子物件執行完整的成員逐一複製。對於每個參考類型的非靜態資料成員,複製建構函式會將該參考繫結至來源參考所繫結的相同物件或函式。

若此定義滿足 constexpr 建構函式(C++23 前)constexpr 函式(C++23 起) 的要求,則產生的複製建構函式為 constexpr

T 具有使用者定義的解構函式或使用者定義的複製賦值運算子,則隱式定義複製建構函式的生成已被棄用。

(C++11 起)

[編輯] 刪除的複製建構函式

若滿足下列任一條件,類別 T 的隱式宣告或顯式預設(C++11 起)複製建構函式將被未定義(C++11 前)定義為刪除的(C++11 起)

  • T 具有右值參考類型的非靜態資料成員。
(C++11 起)
  • M 的解構函式被刪除或(C++11 起)無法從複製建構函式存取,或
  • 應用於尋找 M 複製建構函式的多載解析結果

T 宣告了移動建構函式移動賦值運算子,則類別 T 的隱式宣告複製建構函式被定義為刪除的。

(C++11 起)

[編輯] 平凡複製建構函式

若滿足以下所有條件,則類別 T 的複製建構函式是平凡的:

  • 它不是使用者提供的(即它是隱式定義的或預設的);
  • T 沒有虛擬成員函式;
  • T 沒有虛擬基類;
  • T 的每個直接基底類別選擇的複製建構函式是平凡的;
  • T 的每個非靜態類別類型(或類別類型陣列)成員選擇的複製建構函式是平凡的;

對於非聯集類別,平凡複製建構函式會有效地複製參數的每個純量子物件(包括遞迴地複製子物件的子物件等),且不執行其他任何操作。然而,填充位元組(padding bytes)不需要被複製,甚至只要複製的子物件的值相同,它們的物件表示也不必相同。

TriviallyCopyable(平凡可複製)物件可以透過手動複製其物件表示來複製,例如使用 std::memmove。所有與 C 語言相容的資料類型(POD 類型)都是平凡可複製的。

[編輯] 合格的複製建構函式

若複製建構函式是使用者宣告的,或是隱式宣告且可定義的,則它就是合格的。

(直到 C++11)

若複製建構函式未被刪除,則它是合格的。

(C++11 起)
(直到 C++20)

若滿足以下所有條件,則複製建構函式是合格的:

(自 C++20 起)

合格複製建構函式的平凡性決定了該類別是否為隱式生命週期類型,以及該類別是否為平凡可複製類型

[編輯] 註解

在許多情況下,即使複製建構函式會產生可觀察的副作用,它們也會被最佳化移除,參見複製省略(copy elision)

[編輯] 範例

struct A
{
    int n;
    A(int n = 1) : n(n) {}
    A(const A& a) : n(a.n) {} // user-defined copy constructor
};
 
struct B : A
{
    // implicit default constructor B::B()
    // implicit copy constructor B::B(const B&)
};
 
struct C : B
{
    C() : B() {}
private:
    C(const C&); // non-copyable, C++98 style
};
 
int main()
{
    A a1(7);
    A a2(a1); // calls the copy constructor
 
    B b;
    B b2 = b;
    A a3 = b; // conversion to A& and copy constructor
 
    volatile A va(10);
    // A a4 = va; // compile error
 
    C c;
    // C c2 = c; // compile error
}

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。

DR 應用於 出版時的行為 正確的行為
CWG 1353 C++98 隱式宣告的複製建構函式為未定義的條件
未考慮多維陣列類型
考量這些型別
CWG 2094 C++11 volatile 成員使複製變得不平凡(CWG 問題 496 平凡性不受影響
CWG 2171 C++11 X(X&) = default 是不平凡的 改為平凡的
CWG 2595 C++20 若存在另一個更受約束的複製建構函式,
則複製建構函式不合格
但如果該移動建構函式未滿足其相關限制
在此情況下它可以是合格的

[編輯] 參見

English Deutsch 日本語 中文(简体) 中文(繁體)