Copy and Move Semantics

Shallow and Deep Copying

If a class has only "normal" values in it, such as integers or floating point values, then the copy constructor and copy assignment operator provided by the compiler will automatically give each object a separate copy of those values. Alteration of one object's members does not affect the other. The following program illustrates this:

#include <iostream>

// Define the members that belong to this type
class Point
{
private:
    int x{};
    int y{};

public:
    Point(int xVal, int yVal)
        : x{ xVal }
        , y{ yVal }
    {
    }

    void setX(int newX)
    {
        x = newX;
    }

    void print() const
    {
        std::cout << x << ',' << y << '\n';
    }
};

int main()
{
    Point a{ 3, 5 };
    Point b{ a };

    a.setX(99);

    a.print();
    b.print();

    return 0;
}

Copy: the object b is created as a copy of a. After the copy, a.setX(99) does only modify the member of a. The next prints give 99, 5 for a and 3, 5 for b. Each object has its own x and its own y; the copy was just duplicating the values.

Similarly with assignment, after already having two objects, assigning one to the other causes the target's members to be replaced with copies of the source's members, resulting in two completely independent objects:

#include <iostream>

class Point
{
// Members below this label are private
private:
    int x{};
    int y{};

public:
    Point(int xVal, int yVal)
        : x{ xVal }
        , y{ yVal }
    {
    }

    void setY(int newY)
    {
        y = newY;
    }

    void print() const
    {
        std::cout << x << ',' << y << '\n';
    }
};

int main()
{
    Point a{ 1, 2 };
    Point b{ 8, 9 };

    b = a;

    a.setY(77);

    a.print();
    b.print();

    return 0;
}

After b = a, the two objects both have 1 and 2. The later call to a.setY(77) only affects a. The last prints therefore show different y-values. The assignment did a per-member copy of the integers, not a sharing of storage between the two objects.

Since each object has its own full set of members, "shallow copy" and "deep copy" do not (yet) behave differently. A shallow copy simply means the two objects will point to the same data, while a deep copy indicates the data themselves are duplicated. With typical value members, however, the compiler-generated copy already performs the deep version: all integers are duplicated, and the objects are independently modifiable.

This distinction only matters when a class is used to manage an external resource, most notably a block of memory that the class has allocated. In this case, the default copy constructor will copy only the reference to the external data, and not the data itself. Both instances will therefore appear to share ownership of the external data.

Modifying the data via one instance is seen in the other, and when both instances are destroyed, the data is released twice.

This double deletion behavior is undefined.

A user written copy constructor and copy assignment operator would bypass this by creating a new resource for the destination object, and copying the data from the source resource to it. This is really a deep copy: each object has its own resource; modifications are localized to that one object; each destructor only deletes its own resource.

For the classes we have written so far, classes that contain only normal values, it's all taken care of. The compiler will provide a copy constructor and assignment operator that will produce fresh, independent objects, for free. But as soon as a class begins to take care of an outside resource, the generic copy constructor and assignment operator produce a shallow copy, which is just about never what one wants.

From that point on, the class must provide its own copy operations that duplicate the resource properly.

Until the need for resources manifests itself, the simple member wise copy shown above is fine.

Exercise: Shallow and Deep CopyingStarter code, hints and solutionOpenClose
Guided practiceBeginner · 10–15 min

Practice: Shallow and Deep Copying

Work through the mission, reveal hints only when needed, and compare your result with the model solution.

Your challenge

Change the post-copy setX argument to 42. Predict both Points and label the original construction, copy construction, and later member modification.

Mission checklist

  1. Run the starter as a baseline, then predict the change requested in Your challenge.
  2. Make that change in your editor; use the lesson-specific hints if you need help.
  3. Compile and run your answer, then compare with the worked solution and explain the result.

Starter program

This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.

#include <iostream>

// Define the members that belong to this type
class Point
{
private:
    int x{};
    int y{};

public:
    Point(int xVal, int yVal)
        : x{ xVal }
        , y{ yVal }
    {
    }

    void setX(int newX)
    {
        x = newX;
    }

    void print() const
    {
        std::cout << x << ',' << y << '\n';
    }
};

int main()
{
    Point a{ 3, 5 };
    Point b{ a };

    a.setX(99);

    a.print();
    b.print();

    return 0;
}

Hints

Hint 1

Point stores its coordinates directly as ints, so b receives independent member values when copied from a. There is no shared heap buffer in this example.

Hint 2

Trace a.setX(99) after the copy: it changes a.x only. A class containing an owning raw pointer would need extra work to get this same independence for pointed-to data.

Worked solution

a is ordinarily constructed and b is copy-constructed. Changing a.x to 42 after the copy changes only a; b retains 3,5 because the int members are separate values. No heap resource is shared in this Point example.

#include <iostream>

// Define the members that belong to this type
class Point
{
private:
    int x{};
    int y{};

public:
    Point(int xVal, int yVal)
        : x{ xVal }
        , y{ yVal }
    {
    }

    void setX(int newX)
    {
        x = newX;
    }

    void print() const
    {
        std::cout << x << ',' << y << '\n';
    }
};

int main()
{
    Point a{ 3, 5 };
    Point b{ a };

    a.setX(42);

    a.print();
    b.print();

    return 0;
}

Example output

42,5
3,5

0 comments

No comments yet. Be the first.

Add a comment

About CppLearn

CppLearn is an interactive, free reference for modern C++. In each lesson, you'll find out how the language works, rather than just lines of code that you can copy and paste. We cover concepts starting from beginner lessons on fundamentals and proceed to templates, move semantics, smart pointers, and areas that usually trap or scare C++ learners.