Thursday 23 January 2014

Shallow Copying

Because C++ does not know much about your class, the default copy constructor and default assignment operators it provides use a copying method known as a shallow copy (also known as a memberwise copy). A shallow copy means that C++ copies each member of the class individually using the assignment operator. When classes are simple (eg. do not contain any dynamically allocated memory), this works very well.
For example, let’s take a look at our Cents class:
1
2
3
4
5
6
7
8
9
10
class Cents
{
private:
    int m_nCents;
public:
    Cents(int nCents=0)
    {
        m_nCents = nCents;
    }
};

When C++ does a shallow copy of this class, it will copy m_nCents using the standard integer assignment operator. Since this is exactly what we’d be doing anyway if we wrote our own copy constructor or overloaded assignment operator, there’s really no reason to write our own version of these functions!
However, when designing classes that handle dynamically allocated memory, memberwise (shallow) copying can get us in a lot of trouble! This is because the standard pointer assignment operator just copies the address of the pointer — it does not allocate any memory or copy the contents being pointed to!

Deep Copying

A deep copy duplicates the object or variable being pointed to so that the destination (the object being assigned to) receives it’s own local copy. This way, the destination can do whatever it wants to it’s local copy and the object that was copied from will not be affected. Doing deep copies requires that we write our own copy constructors and overloaded assignment operators.
Let’s go ahead and show how this is done for our MyString class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Copy constructor
MyString::MyString(const MyString& cSource)
{
    // because m_nLength is not a pointer, we can shallow copy it
    m_nLength = cSource.m_nLength;
 
    // m_pchString is a pointer, so we need to deep copy it if it is non-null
    if (cSource.m_pchString)
    {
        // allocate memory for our copy
        m_pchString = new char[m_nLength];
 
        // Copy the string into our newly allocated memory
        strncpy(m_pchString, cSource.m_pchString, m_nLength);
    }
    else
        m_pchString = 0;
}
As you can see, this is quite a bit more involved than a simple shallow copy! First, we have to check to make sure cSource even has a string (line 8). If it does, then we allocate enough memory to hold a copy of that string (line 11). Finally, we have to manually copy the string using strncpy() (line 14).

No comments:

Post a Comment