Skip to content

RAII

Video: Resource Acquisition is Initialization (RAII) Explained in C++

RAII (Resource Acquisition Is Initialization) ensures that resources are properly managed by tying resource lifetime to object lifetime, making code exception-safe and preventing resource leaks. Whenever an object is initialized, C++ automatically calls the constructor - this is when you should acquire resources. Conversely, when an object is destroyed, C++ automatically calls the destructor - this is when you should release resources.

In summary:

  1. Resources are acquired in constructors (initialization)
  2. Resources are released in destructors (cleanup)
  3. Object lifetime determines resource lifetime

The key insight is that C++ guarantees destructors will be called when objects go out of scope, even if exceptions are thrown.

Benefits of RAII

  1. Exception Safety: RAII provides automatic cleanup even when exceptions occur
  2. No Resource Leaks: Resources are automatically released, preventing leaks
  3. Simplified Code: No need for manual cleanup or try/catch blocks for resource management
  4. Performance: Critical for high-frequency trading systems where resource leaks are catastrophic

A good RAII implementation should also provide get(), release(), and reset() methods to allow for more control over the resource.

Additionally, the constructor should be marked [[nodiscard]] to prevent accidental misuse.

Implement a CustomAllocator class that follows RAII principles. The class should allocate a large block of memory in the constructor, provide an allocate(size_t size) method to return sub-blocks, track allocation statistics (total allocated, peak usage), and automatically deallocate the entire block in the destructor. Handle proper memory alignment for the returned pointers.

cpp
// Constructor: Allocate a large block of memory
    CustomAllocator(size_t total_size) {
        // TODO: Initialize member variables
        // TODO: Allocate memory_block using new
        // TODO: Set initial values for tracking
    }

    // Destructor: Deallocate the entire block and report statistics
    ~CustomAllocator() {
        // TODO: Deallocate memory_block
    }

    // Allocate a sub-block of the specified size
    void* allocate(size_t size) {
        // TODO: Check if there's enough space in the block
        // TODO: Handle alignment requirements (align to 8 bytes)
        // TODO: Return pointer to allocated memory
        return nullptr;
    }

    // Print current statistics
    std::size_t get_peak_usage() const {
        return peak_usage;
    }

    std::size_t get_total_allocations() const {
        return total_allocations;
    }
}; 
#include <cstddef>

class CustomAllocator {
private:
    char* memory_block;

    // Data members for tracking statistics
    std::size_t peak_usage{};
    std::size_t total_allocations{};

public: