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

物件生命週期的深度對話:臨時物件、參考綁定與未定義行為

     編輯:關於VC++

序:一個看似簡單的編譯錯誤

假日無 deadline 壓力,閱讀同事代碼時發現:

class T {
public:
    T& ref() { return *this; }
};
void f(T&);
int main() {
    f(T().ref()); // 編譯通過
    // f(T());   // ❌ 編譯錯誤:無法將非常量參考綁定到臨時物件
}

初見以為 f(T()) 應可行,卻報錯「綁定非常量參考到臨時物件」。刪除 .ref() 卻錯誤,保留卻通過——這違背直覺。

大師的解釋:左值與右值的規則

「禁止綁定非常量參考到臨時物件,是為防止隱蔽 bug。若允許,經由轉換運算子產生的臨時物件被修改後銷毀,原物件卻未變,極易誤導程式設計師。」

但為何 f(T().ref()) 合法?

「必須多思考一步:T() 建立右值;右值僅能綁定常量、非 volatile 參考;但函數返回參考型別,其返回值為左值。故 ref() 返回左值,可綁定非常量參考。」

危險的技巧:賦值運算子同樣返回左值

若 f(T() = T()) 合法?賦值運算子返回 T&,同理可繞過檢查。但大師警告:

「此技巧極危險,至少有一種情況導致未定義行為:物件生命週期管理。」

夢境推演:野參考的誕生

構造函數持有參考成員:

class U {
    T& t_;
public:
    U(T& t) : t_(t) {}
};

// 使用賦值技巧建立臨時物件並傳遞
{
    U u( (T() = T()) ); // 臨時物件在 U 建構結束時銷毀
    // u.t_ 成為野參考 (dangling reference)!
}

區塊結束時,臨時 T 物件銷毀,U 內部參考懸空。後續存取 u.t_ 即為未定義行為——如同從未存在的物件。

正確修正:延長生命週期

{
    T tmp;              // 命名物件,生命週期至區塊結束
    U u(tmp);           // 綁定有效物件
    // 安全使用 u
}

核心法則總結 (C++98/03/11/14/17/20 通用)

規則說明
臨時物件 (右值)僅能綁定 const T& 或 T&& (C++11 右值參考)
函數返回參考返回值為左值,可綁定 T&
賦值運算子返回 T&,屬左值
參考成員初始化必須綁定生命週期超過擁有者的物件
延長生命週期唯一方式:綁定到 const T& (臨時物件生命延長至參考銷毀) 或命名變數

現代 C++ 最佳實踐

  • 避免返回區域物件的參考/指標。
  • 參考成員慎用,改用 std::shared_ptr/std::weak_ptr 管理共享所有權。
  • C++11 起優先使用右值參考 (T&&) 實現移動語義,而非濫用臨時物件綁定技巧。
  • 啟用編譯器警告 (-Wall -Wextra -Werror / /W4) 捕獲懸空參考風險。

註腳:ISO/IEC 14882:1998(E) §5.2.3, §8.5.3, §3.10。
作者:Jim Hyslop,Leitch Technology International 高級軟體架構師。

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