Open In App

The Rule of Five in C++

Last Updated : 17 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

The “Rule of  Five” is a guideline for efficient and bug-free programming in C++. The Rule of Five states that,

If any of the below functions is defined for a class, then it is better to define all of them.

It includes the following functions of a class:

  1. Destructor
  2. Copy Constructor
  3. Copy Assignment Operator
  4. Move Constructor
  5. Move Assignment Operator

The Rule of Big Five is an extension of the Rule of Three to include move semantics. The Rule of Three, consists of a destructor, copy constructor, and, copy assignment operator, use all these three functions when you are dealing with dynamically allocated resources Whereas The Rule of Five includes two more functions i.e. move constructor and move assignment operator.

Need for Rule of Five in C++

In C++ “The Rule of Big Five” is needed to properly manage the resources and efficiently handle objects. Following are the important reasons why we should use the Rule of the Big Five:

  • Assume that you have some dynamically allocated resources in the object and you copy them using shallow copy. This will lead to problems like segmentation faults when the source object is destroyed. Similar thing will happen with copy assignment, move constructor and move assignment operator.
  • By implementing Rule of Big Five properly we can make sure that there are no resource leaks. This can be achieved by ensuring that all the dynamically allocated memory or any other resources are released appropriately.

Let’s discuss each of the five special member functions that a class should define in detail

1. Destructor

The Destructor is used for removing/freeing up all the resources that an object has taken throughout its lifetime.With the help of this destructor, we make sure that any resources taken by objects are properly released before the object is no longer in scope.

Syntax

class ClassName {
public:
// Destructor
~ClassName() {
// releasing allocated memory
// Make sure to add the necessary code to release any resources you've acquired, such as dynamic memory or file handles.
}
};

2. Copy Constructor

Copy Constructor is used to make a new object by copying an existing object. Copy constructor is invoked when we use it to pass an object by value or when we make a copy explicitly. mainly we use copy constructor to replicate an already existing object.

Syntax

class ClassName {
public:
// Copy Constructor
ClassName(const ClassName& other) {
// Here's the code for the copy constructor, which performs a deep copy of the resources.
}
};

3. Copy Assignment Operator

Copy Assignment Operator is a special type of function that takes care of assigning the data of one object to another object. It gets called when you use this assignment operator (=) between objects.

Syntax

class ClassName {
public:
// Copy Assignment Operator
ClassName& operator=(const ClassName& other) {
if (this != &other) {
// generate a deep copy of resources
}
return *this;
}
};

4. Move Constructor

Move Constructor is one of the member functions that is used to transfer the ownership of resources from one object to another. This job can easily be done by this move constructor by using a temporary object called rvalue

Syntax

class ClassName {
public:
// Move Constructor
ClassName(ClassName&& other) noexcept //“noexcept” is not a function name but a specifier in C++, does not throw any exceptions
{
// Here's the code for the move constructor,
// The transfer of ownership of resources.
}
};

Explanation: In the above syntax, “noexcept” is used to indicate that the given function, like the move constructor in this case, does not throw any kind of exceptions. The move constructor is specifically designed to handle temporary objects and it requires an rvalue reference (ClassName&& other) as a parameter.

5. Move Assignment Operator

The Move Assignment Operator is comparable to the Move Constructor. It is used when an existing object is assigned the value of an rvalue. It is activated when you use the assignment operator (=) to assign the data of a temporary object(value) to an existing object.

Syntax

class ClassName {
public:
// Move Assignment Operator
ClassName& operator=(ClassName&& other) noexcept {
if (this != &other) {
//code here,
//transfer ownership of resources.
}
return *this;
}
};

Example

The below example demonstrates the use of all five member functions: Destructor, Copy Constructor, Copy Assignment Operator, Move Constructor, and Move Assignment Operator.

C++




// C++ program to demonstrate all 5 member functions
// :Destructor, Copy Constructor, Copy Assignment Operator,
// Move Constructor, and Move Assignment Operator.
  
#include <iostream>
#include <utility> // for using move
using namespace std;
  
class ResourceManager {
private:
    int* data;
    size_t size;
  
public:
    // default constructor
    ResourceManager(size_t sz = 0)
        : data(new int[sz])
        , size(sz)
    {
        cout << "Default Constructor is called" << endl;
    }
  
    // Destructor
    ~ResourceManager()
    {
        delete[] data;
        cout << "Destructor is called" << endl;
    }
  
    // Copy Constructor
    ResourceManager(const ResourceManager& other)
        : data(new int[other.size])
        , size(other.size)
    {
        copy(other.data, other.data + other.size, data);
        cout << "Copy Constructor is called" << endl;
    }
  
    // Copy Assignment Operator
    ResourceManager& operator=(const ResourceManager& other)
    {
        if (this != &other) {
            delete[] data;
            data = new int[other.size];
            size = other.size;
            copy(other.data, other.data + other.size, data);
        }
        cout << "Copy Assignment Operator is called"
             << endl;
        return *this;
    }
  
    // Move Constructor
    ResourceManager(ResourceManager&& other) noexcept
        : data(other.data),
          size(other.size)
    {
        other.data = nullptr;
        other.size = 0;
        cout << "Move Constructor" << endl;
    }
  
    // Move Assignment Operator
    ResourceManager&
    operator=(ResourceManager&& other) noexcept
    {
        if (this != &other) {
            delete[] data;
            data = other.data;
            size = other.size;
            other.data = nullptr;
            other.size = 0;
        }
        cout << "Move Assignment Operator" << endl;
        return *this;
    }
};
  
int main()
{
    // Creating an object using default constructor
    ResourceManager obj1(5);
  
    // Creating an object using Copy constructor
  
    ResourceManager obj2 = obj1;
  
    // Creating an object using Copy assignment operator
    ResourceManager obj3;
    obj3 = obj1;
  
    // Creating an object using Move constructor
    ResourceManager obj4 = move(obj1);
  
    // Creating an object using Move assignment operator
    ResourceManager obj5;
    obj5 = move(obj2);
  
    return 0;
}


Output

Default Constructor is called
Copy Constructor is called
Default Constructor is called
Copy Assignment Operator is called
Move Constructor
Default Constructor is called
Move Assignment Operator
Destructor is called
Destructor is called
Destructor is called
Destructor is called
Destructor is called

Conclusion

In C++ “The Rule of Big Five” is used to ensure that the memory is properly handled i.e. memory allocation and deallocation is done properly and also resource management. It is an extension of Rule of Three. This rule says that we should use or try to use all the five functions (Destructor, Copy Constructor, Copy Assignment Operator, Move Constructor, and Move Assignment Operator) even if initially we require only one so that we can achieve application optimization, less bugs, efficient code and manage the resources efficiently.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads