| 聲明 | 類型 | 分配 | 銷毀 |
value class V { ... };
V v; | 值類型 | 棧 | 作用域結束調用析構器(~V()) |
ref class R { ... };
R r; | 引用類型 | 托管堆(隱式 gcnew) | GC 回收,調用終結器(!R()) |
ref class R { ... };
R^ r = gcnew R(); | 引用類型 | 托管堆 | GC 回收 |
析構器與終結器模式
C++/CLI 引入雙重清理機制:
ref class ResourceHolder {
IntPtr handle_; // 非托管資源
public:
ResourceHolder() { handle_ = Acquire(); }
// 析構器:確定性釋放(對應 IDisposable.Dispose)
~ResourceHolder() {
if (handle_ != IntPtr::Zero) {
Release(handle_);
handle_ = IntPtr::Zero;
}
this->!ResourceHolder(); // 抑制終結器
}
// 終結器:非確定性備援(GC 調用)
!ResourceHolder() {
if (handle_ != IntPtr::Zero) {
Release(handle_);
handle_ = IntPtr::Zero;
}
}
};
~Type() 對應 IDisposable.Dispose(),!Type() 對應 Finalize()。棧上聲明引用類型時,作用域結束自動調用 ~Type(),實現確定性資源釋放(類似 C++ RAII)。
棧對象的實際行為演示
#include <iostream>
using namespace System;
ref class R {
public:
R() { Console::WriteLine("R ctor"); }
~R() { Console::WriteLine("R dtor (Dispose)"); }
!R() { Console::WriteLine("R finalizer"); }
};
value class V {
public:
V(int x) : val(x) { Console::WriteLine("V ctor"); }
~V() { Console::WriteLine("V dtor"); }
int val;
};
int main() {
Console::WriteLine("--- Stack ref class ---");
R r; // 隱式 gcnew,作用域結束調用 ~R()
Console::WriteLine("--- Stack value class ---");
V v(42); // 真棧分配,作用域結束調用 ~V()
Console::WriteLine("--- End of main ---");
return 0;
}
輸出:
--- Stack ref class ---
R ctor
R dtor (Dispose)
--- Stack value class ---
V ctor
V dtor
--- End of main ---
注意:R 的終結器 未調用,因析構器已抑制(GC::SuppressFinalize 隱式調用)。
互操作核心建議
- 值類型用於小型、不可變、高頻數據(如數學向量、顏色),避免裝箱開銷。
- 引用類型用於實體、多態、大型對象,配合
gcnew 明確語義。
- 棧上聲明引用類型(
R r;)僅用於簡單 RAII 場景,複雜生命周期請用 R^ r = gcnew R(); 配合 delete r;(調用 ~R())。
- 非托管資源必須實現析構器/終結器模式,防止洩漏。
- 避免在值類型中持有引用類型字段(隱含裝箱/拷貝語義混淆)。
- 上一篇文章: C++ 異常處理進階:堆棧跟蹤、信號轉換與全局捕獲實戰
- 下一篇文章: C++ 編譯器工作原理揭秘:從源碼到匯編的完整流程
Copyright ©
程式碼之家 All Rights Reserved