首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C++ 拷貝構造函數與賦值運算符:模板陷阱與隱式生成規則

     編輯:關於C語言

驚人的代碼


struct X {
    X() {}
    template X(const T&) { puts("templated copy ctor"); }
    template X& operator=(const T&) { puts("templated assign"); return *this; }
};

int main() {
    X x1;
    X x2(x1);   // 輸出?
    X x3; x3 = x1; // 輸出?
}

**輸出:空!** 兩個模板**均未被調用**。

標準條文解讀 (C++03 12.8/2, 12.8/9)

  • 拷貝構造函數:非模板構造函數,第一參數為 X&, const X&, volatile X&, const volatile X&,且**無其他參數**或其餘參數有默認值。
  • 賦值運算符:非模板、非靜態成員函數,恰好一個參數,類型為 X, X&, const X&, volatile X&, const volatile X&。

關鍵字:**非模板**。帶模板參數的構造/賦值函數**不算**拷貝構造/賦值運算符。

發生了什麼?

  1. 類 X **未顯式聲明**符合標準定義的拷貝構造/賦值運算符。
  2. 2. 編譯器**隱式生成**預設版本:逐成員淺拷貝(此處無成員,故空操作)。 3. 隱式版本匹配更好(精確匹配 const X&),模板版本需推導 T=X,排序較低。 4. 因此調用隱式版本,**無任何輸出**。

正確寫法:顯式聲明


struct X {
    X() {}
    X(const X&) { puts("copy ctor"); }           // 真正的拷貝構造
    X& operator=(const X&) { puts("assign"); return *this; } // 真正的賦值
    // 如需通用構造,放在後面或用 SFINAE 排除 X 自身
    template>>
    X(const T&) { puts("templated ctor"); }
};

C++11 後的新規則

  • = default / = delete 顯式控制隱式生成。
  • 移動構造/賦值(X(X&&), operator=(X&&))若用戶聲明任意構造/析構/賦值,**不會**隱式生成移動操作(Rule of Five)。
  • 模板構造函數若想排除拷貝/移動語義,需配合 std::enable_if 或 Concepts (C++20)。

實戰檢查清單

場景建議
管理資源(指標、句柄、文件)必須顯式實現「五大函數」或 =delete 禁止拷貝,改用移動語義/智能指標
僅含值類型成員可 =default 或依賴隱式
含 const/引用成員無法賦值,必須 =delete 賦值運算符
基類設計虛析構,**protected** 非虛賦值防止切片

總結

**「模板構造 ≠ 拷貝構造」**是 C++ 核心規則之一。隱式生成規則看似簡單,實則暗含「非模板優先、精確匹配優先」的重載決議邏輯。寫資源管理類時,務必顯式 =default/=delete/自定義,別讓編譯器替你決定。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved