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

C++ 函數調用機制深度剖析:值傳遞、引用傳遞、指針傳遞與拷貝構造

     編輯:關於C++

代碼場景

class Coord {
public:
    Coord(int a=0, int b=0) : x(a), y(b) {}
    Coord(const Coord& p) : x(p.x), y(p.y) { cout << "Copy Ctor\n"; }
    ~Coord() { cout << "Dtor\n"; }
    void print() const { cout << "(" << x << "," << y << ")\n"; }
    int getX() const { return x; }
    int getY() const { return y; }
private:
    int x, y;
};

void fun1(Coord p) {  // 值傳遞
    cout << "fun1: "; p.print();
}
void fun2(Coord& p) {  // 引用傳遞
    cout << "fun2: "; p.print();
}
void fun3(Coord* p) {  // 指針傳遞
    cout << "fun3: "; p->print();
}
Coord fun4() {  // 返回值
    Coord tmp(10, 20);
    return tmp;  // NRVO/RVO 優化
}

int main() {
    Coord c1(1, 2);
    cout << "=== 值傳遞 ===\n"; fun1(c1);
    cout << "=== 引用傳遞 ===\n"; fun2(c1);
    cout << "=== 指針傳遞 ===\n"; fun3(&c1);
    cout << "=== 返回值 ===\n"; Coord c2 = fun4(); c2.print();
    return 0;
}

調用過程分析

1. 值傳遞 fun1(c1)

  • 調用拷貝構造函數創建臨時對象 p(輸出 "Copy Ctor")。
  • 函數內操作副本,不影響原對象。
  • 函數結束,調用析構函數銷毀 p(輸出 "Dtor")。

2. 引用傳遞 fun2(c1)

  • 無拷貝,p 直接綁定到 c1。
  • 函數內可修改 c1。
  • 無額外構造/析構開銷。

3. 指針傳遞 fun3(&c1)

  • 傳遞地址值(拷貝指針,極輕量)。
  • 函數內通過指針訪問/修改原對象。
  • 需注意空指針檢查。

4. 返回值 fun4()

  • 理論上:構造 tmp,拷貝構造返回臨時對象,析構 tmp,移動構造/拷貝構造初始化 c2,析構臨時對象。
  • 實際上:編譯器啟用 RVO (Return Value Optimization) / NRVO,直接在調用者棧幀構造 c2,零拷貝。輸出無 "Copy Ctor"。
  • C++17 保證 RVO;C++11 起引入移動語義,即使不優化也調用移動構造(若定義)。

拷貝構造函數 vs 賦值運算符

Coord c3 = c1;  // 拷貝構造(初始化)
Coord c4; c4 = c1;  // 賦值運算符(先構造 c4,再賦值)
  • 拷貝構造:創建新對象。
  • 賦值運算符:修改已存在對象,需處理自賦值、釋放舊資源、分配新資源。

最佳實踐

  1. 參數傳遞:優先 const 引用(const Coord&),避免拷貝且保護原對象。
  2. 需修改原對象:非 const 引用。
  3. 需可選參數/空值:指針(或 std::optional C++17)。
  4. 返回對象:直接返回值,信任 RVO/移動語義,勿手動 new 返回指針。
  5. 類管理資源(指針、句柄):必須實現拷貝構造、賦值運算符、析構函數(三大法則),C++11 另加移動構造、移動賦值(五大法則)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved