C++ 程式中,動態記憶體、檔案控制代碼、GDI 物件等臨時資源的分配與釋放錯綜複雜。異常拋出、多重 return、錯誤碼返回等控制流極易導致資源洩漏。傳統做法到處寫 delete/free/CloseHandle,程式碼雜亂且難以維護。
利用 C++ 物件在區塊結束時自動呼叫解構子的特性,將資源獲取綁定於建構子,釋放綁定於解構子。無論區塊如何離開(正常、return、異常),解構子必定執行,保證資源釋放。
class TMemory {
void* ptr;
public:
explicit TMemory(int size) : ptr(new char[size]) {
memset(ptr, 0, size); // 可選:歸零初始化
}
~TMemory() { delete[] ptr; } // 自動釋放,ptr 為 nullptr 時 delete 安全
void* get() const { return ptr; }
// 禁止複製,避免雙重釋放(C++11 可用 =delete)
TMemory(const TMemory&) = delete;
TMemory& operator=(const TMemory&) = delete;
};
// 使用範例
void some_function(int size) {
TMemory mem(size); // 獲取資源
char* str = static_cast<char*>(mem.get());
risky_operation(str); // 即使拋出異常
return; // 或提前返回
} // 區塊結束,~TMemory() 自動釋放
class TWaitCursor {
HCURSOR oldCursor;
public:
TWaitCursor() : oldCursor(SetCursor(LoadCursor(nullptr, IDC_WAIT))) {}
~TWaitCursor() { SetCursor(oldCursor); } // 自動還原
TWaitCursor(const TWaitCursor&) = delete;
TWaitCursor& operator=(const TWaitCursor&) = delete;
};
// 使用範例
void long_operation() {
do_preparation();
TWaitCursor wait; // 進入區塊即切換為等待游標
heavy_computation(); // 耗時操作
// 任何異常或 return 都會觸發解構子還原游標
}
mem、wait,語意清晰。TWaitCursor wait();(被誤判為函式宣告),必須寫成 TWaitCursor wait;。同樣模式可套用至:
FILE*/HANDLE)EnterCriticalSection/LeaveCriticalSection)C++11 起提供標準化 RAII 組件:
std::unique_ptr、std::shared_ptr:記憶體管理std::lock_guard、std::unique_lock:鎖管理std::fstream:檔案流自動關閉實務建議:優先使用標準庫組件,僅在特殊平台資源(如 Win32 API 控制代碼)無標準對應時自行封裝 RAII 包裝器。
RAII 是 C++ 資源管理的基石。透過簡單的類封裝,將「獲取即初始化、離開即釋放」落實到每個區塊,徹底消除資源洩漏隱憂,讓程式碼更簡潔、健壯、可維護。