Tutorial: What is a Copy Constructor?

Posted by Matt | Filed under , ,

Take a look at this C++ class:

class CMyClass
{
private:
	int *m_pPtr;
public:
	CMyClass()
	:	m_pPtr(NULL)
	{
	}

	void Set(int *pPtr)
	{
		// Clean up
		if (m_pPtr != NULL)
		{
			delete m_pPtr;
			m_pPtr = NULL;
		}

		// Assign
		if (pPtr != NULL)
		{
			// Make a copy
			m_pPtr = new int;
			*m_pPtr = *pPtr;
		}
	}

	int *Get() const
	{
		return m_pPtr;
	}

	~CMyClass()
	{
		// Clean up
		if (m_pPtr != NULL)
		{
			delete m_pPtr;
			m_pPtr = NULL;
		}
	}
};

You'll notice that there is a pointer member variable.

If you use the class as follows, you won't have any problems:

void MyFunction()
{
	CMyClass var;
	int i = 5;
	var.Set(&i);
	int *pPtr = var.Get();
}

However, you will have problems if you do this:

void MyFunction(CMyClass var2)
{
	int *pPtr = var2.Get();
}

void MyOtherFuncion()
{
	CMyClass var;
	int i = 5;
	var.Set(&i);
	MyFunction(var);
	int *pPtr = var.Get();
}

Why?

Because when MyFunction() is called, the variable var is copied to var2.  When this happens, if you inspect the pointer of var and var2, you'll notice that the m_pPtr member variables not only contain the same value (5, as is correct to think), but they also point to the exact same address in memory (not expected).

In the above example, because the m_pPtr member variables point to the same address in memory, that memory will be deleted twice:  once by var2 when exiting MyFunction(), but also by var when exiting MyOtherFunction().  This should result in a crash.

The solution?  Copy constructors.

If you add the following function to the above class, your problem is solved:

class CMyClass
{
	// Other functions

	CMyClass(const CMyClass &other)
	:	m_pPtr(NULL)
	{
		Set(other.m_pPtr);
	}
};

If you run the previous problematic code with the new copy constructor, the program won't have the same issues anymore.  The m_pPtr member variables will continue to contain the same value (5), but they will point to different addresses in memory.  This will allow each to delete it's own copy in it's destructor.

Why pass other by reference (by using &) ?

If other was not passed by reference, then the copy constructor would be called when calling the copy constructor and this would lead to a (potential) infinite loop.

Why is this different than operator = ?

While the operator = and the copy constructor may perform very similar functionality, they are each called in different contexts.

CMyClass CreateVar()
{
	CMyClass var;
	int i = 10;
	var.Set(&i);
	return var; // Copy constructor
}

void MyFunction()
{
	CMyClass var;
	int i = 5;
	var.Set(&i);
	CMyClass var2(var); // Copy Constructor
	CMyClass var3 = var; // operator =
	CMyClass var4;
	var4 = var; // operator =
	CMyClass var5 = CreateVar(); // operator =
}

This is assuming that the compiler doesn't change things by optimizing (especially in the call to CreateVar()).

I hope this helps.

Thus endeth the lesson.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Add comment


(Will show your Gravatar icon)  

  Country flag

biuquote
  • Comment
  • Preview
Loading