C++ 手動管理臨時資源(記憶體、游標、鎖、檔案控制代碼)極易因**多重返回路徑**、**例外拋出**、**維護修改**導致洩漏。傳統做法在每個出口重複釋放代碼,繁瑣且錯誤頻發。
利用**區域物件的解構函數自動執行**特性,將資源獲取綁定建構、釋放綁定解構,實現**零成本自動化管理**。
class TMemory {
public:
void* Ptr;
public:
explicit TMemory(int Size) {
Ptr = new char[Size];
::ZeroMemory(Ptr, Size); // WinAPI 清零
}
~TMemory() {
if (Ptr) delete[] reinterpret_cast(Ptr); // 陣列需用 delete[]
}
// 禁止複製(C++11 可用 =delete)
TMemory(const TMemory&) = delete;
TMemory& operator=(const TMemory&) = delete;
};
// 使用範例
void TMainForm::ProcessData(int Size) {
TMemory Mem(Size); // 建構:配置記憶體
char* Str = (char*)Mem.Ptr; // 取得指標
SomeFunction(Str); // 可能拋出例外
return; // 直接返回,解構自動釋放
// 即使 SomeFunction 拋出例外,Mem 解構仍保證執行
}
delete[],否則未定義行為=delete)bad_alloc)不會進入解構,無洩漏風險
#pragma warn -bei // 關閉列舉指派警告
class TWaitCursor {
private:
TCursor OldCursor;
public:
TWaitCursor() : OldCursor(Screen->Cursor) {
Screen->Cursor = crHourGlass;
}
~TWaitCursor() {
Screen->Cursor = OldCursor;
}
};
// 使用範例
void TMainForm::LongOperation() {
SomeQuickOp();
TWaitCursor Wait; // 進入:游標變沙漏
SlowFunction(); // 耗時操作,可能拋出例外
return; // 返回:解構自動恢復游標
}
TWaitCursor Wait; // 正確:建構物件
TWaitCursor Wait(); // 錯誤:這是函數宣告(最令人困惑的 C++ 語法陷阱)
// 通用範圍守衛(C++11)
template
class ScopeGuard {
F Func_;
bool Active_;
public:
explicit ScopeGuard(F f) : Func_(std::move(f)), Active_(true) {}
~ScopeGuard() { if (Active_) Func_(); }
void Dismiss() { Active_ = false; }
ScopeGuard(ScopeGuard&& rhs) : Func_(std::move(rhs.Func_)), Active_(rhs.Active_) { rhs.Dismiss(); }
};
template
ScopeGuard MakeGuard(F&& f) { return ScopeGuard(std::forward(f)); }
// 使用
void Foo() {
auto guard = MakeGuard([]{ Screen->Cursor = crDefault; });
Screen->Cursor = crHourGlass;
// ...
} // 離開作用域自動恢復
| 資源類型 | 標準庫 RAII 包裝 | 適用標準 |
|---|---|---|
| 動態記憶體 | std::unique_ptr, std::shared_ptr | C++11 |
| 陣列/緩衝區 | std::vector, std::string, std::unique_ptr | C++98/11 |
| 鎖 | std::lock_guard, std::unique_lock | C++11 |
| 檔案 | std::fstream (RAII 關閉) | C++98 |
| 通用範圍清理 | std::scope_exit (提案中) / 自製 ScopeGuard | C++23/自製 |