DEV Community

Cover image for RAII Explained: Why C++ Doesn't Need a Garbage Collector
Sk
Sk

Posted on

RAII Explained: Why C++ Doesn't Need a Garbage Collector

RAII is a core C++ philosophy you can't skip. It ties resources; files, memory, locks, directly to object lifetimes and scope.

Think of it as a localized garbage collector(gc) under your control.

It's a blueprint that tells the compiler to insert cleanup code at crucial spots; like defer in Zig or Go, that runs at the end of a scope.

By "blueprint" I mean, a way of structuring code(the rule of 5 below) so the compiler automatically generates cleanup tied to scope.


The Rule of Five

Here's the classic RAII skeleton:

class ResourceHolder { public: ResourceHolder(); // Constructor ~ResourceHolder(); // Destructor ResourceHolder(const ResourceHolder&); // Copy constructor ResourceHolder& operator=(const ResourceHolder&); // Copy assignment ResourceHolder(ResourceHolder&&) noexcept; // Move constructor ResourceHolder& operator=(ResourceHolder&&) noexcept; // Move assignment }; 
Enter fullscreen mode Exit fullscreen mode

Want to ban copying? Delete it:

ResourceHolder(const ResourceHolder&) = delete; ResourceHolder& operator=(const ResourceHolder&) = delete; 
Enter fullscreen mode Exit fullscreen mode

Once you grasp self-regulating objects, you learn to lean on smart pointers for ownership:

std::unique_ptr<ResourceHolder> a; a = std::make_unique<ResourceHolder>(); // one owner at a time std::shared_ptr<ResourceHolder> b; // multiple owners allowed 
Enter fullscreen mode Exit fullscreen mode

Smart pointers track ownership automatically, once no one owns an object, it cleans itself up(like a localized gc).


The RAII Template With Examples

For RAII, the bare minimum is:

  • a constructor (acquire the resource),
  • a destructor (release the resource).

Copy/move can be defaulted or customized depending on your needs.

Example: managing a file safely.

class File { std::fstream file; public: File(const std::string& filename, std::ios::openmode mode) : file(filename, mode) { if (!file.is_open()) { throw std::runtime_error("Failed to open file: " + filename); } } ~File() { if (file.is_open()) { file.close(); } } // Prevent copying File(const File&) = delete; File& operator=(const File&) = delete; // Allow moving File(File&& other) noexcept : file(std::move(other.file)) {} File& operator=(File&& other) noexcept { if (this != &other) { file = std::move(other.file); } return *this; } }; 
Enter fullscreen mode Exit fullscreen mode

Standard Library RAII

RAII is also baked into the standard template library(STL).

void simple_example() { std::vector<int> numbers; // acquire memory numbers.push_back(42); // use resource // cleanup happens automatically when numbers goes out of scope } 
Enter fullscreen mode Exit fullscreen mode

Even better: RAII plays nicely with exceptions.

void safe_function() { std::ifstream file("data.txt"); std::vector<int> buffer(1024); // Resources freed automatically, // even if we return early or throw. } 
Enter fullscreen mode Exit fullscreen mode

RAII in Structs

C++ doesn’t care if you use struct or class, the only difference is default visibility (public for structs vs private). Both can do RAII.

struct FileHandler { std::unique_ptr<std::fstream> file; FileHandler(const std::string& filename) { file = std::make_unique<std::fstream>(filename, std::ios::in | std::ios::out); if (!file->is_open()) { throw std::runtime_error("Failed to open file"); } } ~FileHandler() { if (file && file->is_open()) { file->close(); } } FileHandler(const FileHandler&) = delete; FileHandler& operator=(const FileHandler&) = delete; FileHandler(FileHandler&&) = default; FileHandler& operator=(FileHandler&&) = default; void write(const std::string& content) { if (file) *file << content; } }; 
Enter fullscreen mode Exit fullscreen mode

Wrap Up

RAII is the beating heart of C++:

  • Resources tied to object lifetimes.
  • Automatic cleanup through constructors/destructors.
  • The Rule of Five to control creation, destruction, copying, and moving.
  • Smart pointers for ownership.
  • Built-in guarantees, even with exceptions.

Adopt RAII early and your C++ journey will get way easier.

Top comments (0)