Finally, the rule of five in C++

Ok, we’ve talked in detail about the special copy and move methods. It’s time to put them together in a reasonable example. Suppose we have the Bond class as defined in our previous examples. We are going to define a Portfolio class that represents a collection of Bonds. The rule of five refers to the four methods we have discussed so far, along with the destructor. The destructor is just a method that frees up whatever resources your class has a reference to. The rule of five states that if you define any of these five special methods, you ought to define them all.

Let’s look at the code.

#include <string>
#include <algorithm>

class Portfolio
{
private:
	std::string Name;
	Bond* Bonds;
	int Size;
public:
	Portfolio(std::string name, Bond* bonds, int size) : Name(name), Bonds(bonds), Size(size)
	{
	}

	Portfolio(const Portfolio& lhs) : Name(lhs.Name)
	{
		std::copy(lhs.Bonds, lhs.Bonds + lhs.Size, Bonds);
	}

	Portfolio& operator=(const Portfolio& lhs)
	{
		if(&lhs != this)
		{
			delete[] Bonds;
		        std::copy(lhs.Bonds, lhs.Bonds + lhs.Size, Bonds);	
			Name = lhs.Name;
			Size = lhs.Size;
		}
		return *this;
	}
		
	Portfolio(Portfolio&& lhs) : Name(lhs.Name), Bonds(lhs.Bonds)
	{
		lhs.Bonds = nullptr;
		lhs.Size = 0;
	}

	Portfolio& operator=(Portfolio&& lhs)
	{
		if(&lhs != this)
		{
			delete[] Bonds;
			Bonds = lhs.Bonds;	
			Name = lhs.Name;
			Size = lhs.Size;
			lhs.Size = 0;
			lhs.Bonds = nullptr;
		}
		return *this;
	}

	~Portfolio()
	{
		delete[] Bonds;
	}
};

Now this code isn’t perfect, in fact we’ll be refining it in future posts. But I think it is a good demonstration of the various special methods in action.

Our Portfolio class manages a resource, a block of memory containing Bond objects. Let’s look at the copy methods first. Whenever we copy a portfolio we want to make a copy of it’s set of bonds. So our copy construction uses the std::copy function to make a deep copy of this resource. When we copy assign, we first free whatever memory we currently have a pointer to. Then we do a deep copy of the array of Bonds. Also, when assigning we check to make sure that we aren’t self assigning.

When we move, we don’t need to copy the entire portfolio of bonds. So, in the move constructor we just copy the pointer to the array, rather than copying its contents. Now that we have moved our array into a new object we don’t want to leave another Portfolio with a pointer to it, so we set the array pointer in the source object to nullptr. Just like with copy assignment, when move assigning, first we check for self assignment. Then we delete the memory we currently have a pointer to, and copy the pointer from the source object. Finally, as before, we set the source object’s pointer to nullptr.

Leave a Reply

Your email address will not be published. Required fields are marked *