Copy and Move Semantics

Copy Constructors

A constructor that produces a new object as a copy of another object of the same type is called a copy constructor. If none is supplied by the programmer, the compiler produces an automatic version that performs a simple, member by member copy.

The following program relies on the automatic copy constructor:

#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 print() const
    {
        std::cout << x << ',' << y << '\n';
    }
};

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

    return 0;
}

The object a is created by the standard constructor. In the line Point b{ a };, a second object b is created and initialized by copying the existing object a. Because the programmer did not provide a copy constructor, the automatically generated version is used, and copies the values of x and y from a into b. The call to print on b outputs 3,5.

The compiler generated copy constructor is not visible. However, by writing one explicitly, we can observe its effect. Such a constructor almost always has a constant reference to an object of the same type as a parameter; passing the parameter by value would cause an infinite series of copy construction calls.

#include <iostream>

class Point
{
private:
    int x{};
    int y{};

public:
    Point(int xVal, int yVal)
        : x{ xVal }
        , y{ yVal }
    {
        std::cout << "ordinary constructor\n";
    }

    // Bind by reference without allowing modification through it
    Point(const Point& other)
        : x{ other.x }
        , y{ other.y }
    {
        std::cout << "copy constructor\n";
    }

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

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

    return 0;
}

The explicit copy constructor Point(const Point& other) is also declared. When Point b{ a }; is executed during the execution of main, the copy constructor is invoked. other is bound to a, and the body of the copy constructor is executed. The members of the newly created object b are initialized using the corresponding members of other, and "copy constructor" is printed to the output.

The output "ordinary constructor" will only appear for object a.

The next call to print shows 3,5 as before.

A constant reference parameter for a copy constructor has two purposes. First, if the parameter is passed by value (e.g., Point other), its initialization must be done with a copy constructor. This implies a recursive invocation of the copy constructor that continues until it reaches infinity.

A reference does not incur this problem since it binds directly to an existing object, thus it doesn't call a copy constructor during initialization.

Second, a constant reference parameter allows binding to temporary objects or existing constant objects.

An object can be created by copy construction not just in a declaration but also when it's passed by value into a function or returned by value from a function.

#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 }
    {
    }

    Point(const Point& other)
        : x{ other.x }
        , y{ other.y }
    {
        std::cout << "copy constructor\n";
    }

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

void show(Point p)
{
    p.print();
}

int main()
{
    Point a{ 7, 11 };
    show(a);

    return 0;
}

In the call show(a), an object is constructed to be passed to p. When show(a) is called, the constructor that constructs this argument is invoked first, hence outputting "copy constructor" before any of the code within show executes. Because p is a separate object within show, it can be modified locally without affecting the object a. The argument object p is then destroyed normally when the function show exits.

When additional work is required that can't be accomplished with simple copying, a user defined copy constructor must be specified by the programmer. However, for classes that deal with no resources, the automatically supplied version will generally suffice, and explicit implementation is necessary only if the copy operation needs to be explicitly noticed or if more elaborate handling is necessary. The presence of one copy constructor in a class makes it the designated one; the compiler won't consider providing another implicit version.

Exercise: Copy ConstructorsStarter code, hints and solutionOpenClose
Guided practiceBeginner · 10–15 min

Practice: Copy Constructors

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

Your challenge

Copy-construct a third Point from b and print it. Distinguish creating the new object from assigning to one that already exists.

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 print() const
    {
        std::cout << x << ',' << y << '\n';
    }
};

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

    return 0;
}

Hints

Hint 1

Point b{a} creates a new object from an existing one. No copy constructor is written, so the compiler-generated copy copies the two int members.

Hint 2

Use Point c{b} to create a new object, then call c.print(). This is initialization; c = b would instead require c to exist already.

Worked solution

A third Point is copy-constructed from b. Its copied coordinates are 3,5, independent of the already-existing objects. Initialization from an object invokes copy construction, not copy assignment.

#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 print() const
    {
        std::cout << x << ',' << y << '\n';
    }
};

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

    Point c{b};
    c.print();
    return 0;
}

Example output

3,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.