RAII
Resource Acquisition Is Initialization
๐ What is RAII?
RAII (Resource Acquisition Is Initialization) is a C++ programming technique where resource management is tied to object lifetime, ensuring automatic cleanup and exception safety.
class FileHandler {
FILE* file;
public:
FileHandler(const char* name) : file(fopen(name, "r")) {}
~FileHandler() { if(file) fclose(file); } // Automatic cleanup
};
Result:
File automatically closed when object is destroyed
RAII Principles
Acquire in Constructor
Get resources when object is created
Resource() { acquire(); }
Release in Destructor
Free resources when object is destroyed
~Resource() { release(); }
Exception Safety
Guaranteed cleanup even with exceptions
// Always cleaned up
Automatic Management
No manual resource tracking needed
// No forget to cleanup
๐น File Management Example
RAII (Resource Acquisition Is Initialization) ensures files are automatically closed when they go out of
scope, even if exceptions occur. By wrapping file handles in classes like std::fstream,
the destructor guarantees cleanup. For example, opening a file in a constructor and closing it in the destructor
prevents resource leaks. This pattern is fundamental to exception-safe C++, simplifying resource management and
eliminating manual cleanup calls, which reduces bugs and improves code reliability.
#include <iostream>
#include <fstream>
#include <stdexcept>
class SafeFile {
private:
std::ifstream file;
public:
SafeFile(const std::string& filename) : file(filename) {
if (!file.is_open()) {
throw std::runtime_error("Cannot open file");
}
std::cout << "File opened successfully\n";
}
~SafeFile() {
if (file.is_open()) {
file.close();
std::cout << "File closed automatically\n";
}
}
std::string readLine() {
std::string line;
std::getline(file, line);
return line;
}
};
int main() {
try {
SafeFile myFile("data.txt");
// File is automatically closed when myFile goes out of scope
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
}
return 0;
}
Output:
File opened successfully
File closed automatically
๐น Memory Management Example
RAII manages dynamic memory automatically using smart pointers like std::unique_ptr, preventing
leaks and ensuring timely deallocation. When a unique_ptr goes out of scope, its
destructor frees the associated memory. For example, auto arr = std::make_unique<int[]>(5); allocates
an array that is automatically freed. This eliminates manual delete calls, enhances exception safety,
and makes memory management deterministic, which is crucial for robust, maintainable applications.
#include <iostream>
class IntArray {
private:
int* data;
size_t size;
public:
IntArray(size_t n) : size(n), data(new int[n]) {
std::cout << "Array of " << size << " integers allocated\n";
for (size_t i = 0; i < size; ++i) {
data[i] = i * 10;
}
}
~IntArray() {
delete[] data;
std::cout << "Array memory freed automatically\n";
}
int& operator[](size_t index) {
return data[index];
}
size_t getSize() const { return size; }
};
int main() {
{
IntArray arr(5);
std::cout << "arr[2] = " << arr[2] << std::endl;
} // arr destructor called here automatically
std::cout << "Program continues...\n";
return 0;
}
Output:
Array of 5 integers allocated
arr[2] = 20
Array memory freed automatically
Program continues...
๐น Lock Management Example
RAII simplifies thread synchronization by automatically acquiring and releasing locks using classes like
std::lock_guard. The lock is acquired in the constructor and released in the destructor,
ensuring mutual exclusion even during exceptions. For example, std::lock_guard lock(mtx); protects a
critical section. This pattern prevents deadlocks from forgotten unlocks and makes multithreaded code safer and
cleaner, which is essential for concurrent programming.
#include <iostream>
#include <mutex>
class ThreadSafeCounter {
private:
int count = 0;
mutable std::mutex mtx;
public:
void increment() {
std::lock_guard<std::mutex> lock(mtx); // RAII lock
++count;
std::cout << "Count incremented to: " << count << std::endl;
// lock automatically released when lock goes out of scope
}
int getValue() const {
std::lock_guard<std::mutex> lock(mtx); // RAII lock
return count;
// lock automatically released
}
};
int main() {
ThreadSafeCounter counter;
counter.increment();
counter.increment();
std::cout << "Final count: " << counter.getValue() << std::endl;
return 0;
}
Output:
Count incremented to: 1
Count incremented to: 2
Final count: 2