Giao diện
🔒 RAII — The Heart of C++
RAII = Resource Acquisition Is Initialization. Tài nguyên được tự động giải phóng khi object ra khỏi scope.
Analogy: Khóa cửa tự động
┌─────────────────────────────────────────────────────────────────┐
│ AUTO-LOCKING DOOR ANALOGY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Manual Lock (new/delete): │
│ ───────────────────────── │
│ 1. Mở cửa │
│ 2. Vào phòng │
│ 3. Làm việc │
│ 4. NHỚ khóa cửa khi ra ← Có thể quên! │
│ │
│ Auto-Lock (RAII): │
│ ───────────────── │
│ 1. Quẹt thẻ vào phòng (acquire) │
│ 2. Làm việc │
│ 3. Ra khỏi phòng → Cửa TỰ ĐỘNG khóa │
│ │
│ RAII = Cửa tự động khóa khi bạn rời đi │
│ Không thể quên, không thể sai! │
│ │
└─────────────────────────────────────────────────────────────────┘RAII Principle
cpp
class Resource {
public:
// Constructor: ACQUIRE resource
Resource() {
// Open file, allocate memory, lock mutex, etc.
}
// Destructor: RELEASE resource (automatic!)
~Resource() {
// Close file, free memory, unlock mutex, etc.
}
};
void useResource() {
Resource r; // Constructor called → resource acquired
// Use resource...
doSomething(r);
mayThrowException(); // Even if exception!
} // ← Destructor called → resource released AUTOMATICALLYExample: File Handle
❌ Without RAII
cpp
void readFile_bad(const char* filename) {
FILE* file = fopen(filename, "r");
if (!file) return;
char buffer[1024];
while (fgets(buffer, sizeof(buffer), file)) {
if (shouldStop(buffer)) {
// Oops! Forgot to close file!
return;
}
process(buffer);
}
fclose(file); // Only reaches here if no early return
}✅ With RAII
cpp
class FileHandle {
FILE* file_;
public:
explicit FileHandle(const char* filename)
: file_(fopen(filename, "r")) {}
~FileHandle() {
if (file_) fclose(file_); // Auto close!
}
FILE* get() const { return file_; }
// Prevent copying
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
};
void readFile_good(const char* filename) {
FileHandle file(filename); // Open in constructor
if (!file.get()) return;
char buffer[1024];
while (fgets(buffer, sizeof(buffer), file.get())) {
if (shouldStop(buffer)) {
return; // ✅ File auto-closed by destructor!
}
process(buffer);
}
} // ← Destructor closes file automaticallyExample: Lock Guard
cpp
#include <mutex>
std::mutex mtx;
int sharedData = 0;
// ❌ Manual lock - dangerous
void increment_bad() {
mtx.lock();
sharedData++;
if (sharedData > 100) {
return; // 💀 Forgot to unlock!
}
mtx.unlock();
}
// ✅ RAII lock - safe
void increment_good() {
std::lock_guard<std::mutex> lock(mtx); // Lock acquired
sharedData++;
if (sharedData > 100) {
return; // ✅ Auto unlock on return!
}
} // ← Auto unlock on scope exitRAII Guarantees
┌─────────────────────────────────────────────────────────────────┐
│ RAII GUARANTEES │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ✅ Normal exit → Destructor called │
│ ✅ Return early → Destructor called │
│ ✅ Exception thrown → Destructor called │
│ ✅ Break/continue → Destructor called │
│ │
│ The ONLY way to skip destructor: │
│ ❌ std::terminate() │
│ ❌ std::abort() │
│ ❌ std::_Exit() │
│ │
└─────────────────────────────────────────────────────────────────┘Standard Library RAII Classes
| Resource | RAII Wrapper |
|---|---|
| Memory | std::unique_ptr, std::shared_ptr |
| Mutex | std::lock_guard, std::unique_lock |
| File | std::fstream |
| Thread | std::jthread (C++20) |
Custom RAII Class Template
cpp
template<typename T, typename Deleter>
class ScopeGuard {
T resource_;
Deleter deleter_;
bool released_ = false;
public:
ScopeGuard(T resource, Deleter deleter)
: resource_(resource), deleter_(deleter) {}
~ScopeGuard() {
if (!released_) {
deleter_(resource_);
}
}
T get() const { return resource_; }
void release() { released_ = true; }
// Non-copyable
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
};
// Usage
void example() {
auto* handle = acquireHandle();
ScopeGuard guard(handle, [](auto* h) { releaseHandle(h); });
// Use handle...
// Auto-released when guard goes out of scope
}📚 Tổng kết
| Aspect | Description |
|---|---|
| Acquire | In constructor |
| Release | In destructor (automatic!) |
| Exception safe | Yes, always |
| Never forget | Compiler guarantees cleanup |
➡️ Tiếp theo
RAII cho memory = Smart Pointers. Bắt đầu với lựa chọn mặc định:
unique_ptr → — Exclusive ownership.