Skip to content

Rule of Five

The Rule of Five is a fundamental C++ guideline that states: If a class defines any one of the five special member functions, it should probably explicitly define all five of them. This rule ensures proper resource management and prevents common memory-related bugs.

By default, the compiler will generate the default implementation for special member functions, but if you define your own, the compiler will not generate the default implementation. This can lead to bugs and memory leaks.

If you have a complex class that requires custom behavior in one of the five special member functions, chances are that you will need custom behavior in all five of them.

The Five Special Member Functions

  1. Destructor (~ClassName())
  2. Copy Constructor (ClassName(const ClassName& other))
  3. Copy Assignment Operator (ClassName& operator=(const ClassName& other))
  4. Move Constructor (ClassName(ClassName&& other) noexcept)
  5. Move Assignment Operator (ClassName& operator=(ClassName&& other) noexcept)

Why the Rule of Five Exists

When a class manages resources (memory, file handles, network connections, etc.), the compiler-generated default implementations are often insufficient and can lead to:

  • Double deletion: Multiple objects trying to delete the same resource
  • Memory leaks: Resources not being properly cleaned up
  • Shallow copying: Multiple objects sharing the same resource incorrectly
  • Use after free: Accessing deallocated memory

Exception Safety and Best Practices

Copy-and-Swap Idiom

A more robust approach for assignment operators is to define a nothrow swap function and use it in the assignment operator. This makes the assignment operator safe from self-assignment (statements like a = a), and ensures that if the copy fails, the original object is not modified.

cpp
class MyString {
    // ... other members ...

    // Copy assignment using copy-and-swap
    MyString& operator=(MyString other) {  // Pass by value (copy)
        swap(*this, other);                // Swap with copy
        return *this;                      // Copy destructs automatically
    }

    friend void swap(MyString& first, MyString& second) noexcept {
        std::swap(first.data, second.data);
        std::swap(first.size, second.size);
    }
};

Rule of Zero

The Rule of Zero is a modern best practice that states: If a class doesn't manage any resources, don't define any special member functions. Smart pointers and standard containers automatically manage resources for you, and any class using them doesn't need to define any special member functions.

Key Takeaway: If your class manages resources directly (raw pointers, file handles, etc.), implement all five special member functions explicitly to ensure correct behavior.

Your Task

You'll be impementing a ResourceManager class to manage a dynamically allocated array of integers. The class should follow the Rule of Five and be exception safe.

Implement a ResourceManager class to manage a dynamically allocated array of integers. The class should follow the Rule of Five. Include a constructor that takes a size parameter and allocates the array.

cpp
// TODO: Implement a ResourceManager class that manages a dynamically allocated 
// array of integers. The class should follow the Rule of Five by implementing 
// all five special member functions:
//
// 1. Destructor
// 2. Copy constructor
// 3. Copy assignment operator  
// 4. Move constructor
// 5. Move assignment operator
//
// The class should have:
// - A constructor that takes a size parameter and allocates an array
// - A method to get the size
// - Proper resource management to prevent memory leaks and double deletion

class ResourceManager {
    // Your implementation here

    int get_size() const {
        // TODO: Return the size of the array
        return 0;
    }
};