Search

9.11 — The copy constructor and overloading the assignment operator

Although using the assignment operator is fairly straightforward, correctly implementing an overloaded assignment operator can be a little more tricky than you might anticipate. There are two primary reasons for this. First, there are some cases where the assignment operator isn’t called when you might expect it to be. Second, there are some issues in dealing with dynamically allocated memory (which we will cover in the next lesson).

The assignment operator is used to copy the values from one object to another already existing object. The key words here are “already existing”. Consider the following example:

In this case, cNancy has already been created by the time the assignment is executed. Consequently, the Cents assignment operator is called. The assignment operator must be overloaded as a member function.

What happens if the object being copied into does not already exist? To understand what happens in that case, we need to talk about the copy constructor.

The copy constructor

Consider the following example:

Because the second statement uses an equals symbol in it, you might expect that it calls the assignment operator. However, it doesn’t! It actually calls a special type of constructor called a copy constructor. A copy constructor is a special constructor that initializes a new object from an existing object.

The purpose of the copy constructor and the assignment operator are almost equivalent -- both copy one object to another. However, the assignment operator copies to existing objects, and the copy constructor copies to newly created objects.

The difference between the copy constructor and the assignment operator causes a lot of confusion for new programmers, but it’s really not all that difficult. Summarizing:

  • If a new object has to be created before the copying can occur, the copy constructor is used.
  • If a new object does not have to be created before the copying can occur, the assignment operator is used.

There are three general cases where the copy constructor is called instead of the assignment operator:

  1. When instantiating one object and initializing it with values from another object (as in the example above).
  2. When passing an object by value.
  3. When an object is returned from a function by value.

In each of these cases, a new variable needs to be created before the values can be copied -- hence the use of the copy constructor.

Because the copy constructor and assignment operator essentially do the same job (they are just called in different cases), the code needed to implement them is almost identical.

An overloaded assignment operator and copy constructor example

Now that you understand the difference between the copy constructor and assignment operator, let’s see how they are implemented. For simple classes such as our Cents class, it is very straightforward.

Here is a simplified version of our Cents class:

First, let’s add the copy constructor. Thinking about this logically, because it is a constructor, it needs to be named Cents. Because it needs to copy an existing object, it needs to take a Cents object as a parameter. And finally, because it is a constructor, it doesn’t have a return type. Putting all of these things together, here is our Cents class with a copy constructor.

A copy constructor looks just like a normal constructor that takes a parameter of the class type. However, there are two things which are worth explicitly mentioning. First, because our copy constructor is a member of Cents, and our parameter is a Cents, we can directly access the internal private data of our parameter. Second, the parameter MUST be passed by reference, and not by value. Can you figure out why?

The answer lies above in the list that shows the cases where a copy constructor is called. A copy constructor is called when a parameter is passed by value. If we pass our cSource parameter by value, it would need to call the copy constructor to do so. But calling the copy constructor again would mean the parameter is passed by value again, requiring another call to the copy constructor. This would result in an infinite recursion (well, until the stack memory ran out and the program crashed). Fortunately, modern C++ compilers will produce an error if you try to do this:

C:\Test.cpp(431) : error C2652: 'Cents' : illegal copy constructor: first parameter must not be a 'Cents'

The first parameter in this case must be a reference to a Cents!

Now let’s overload the assignment operator. Following the same logic, the prototype and implementation are fairly straightforward:

A couple of things to note here: First, the line that does the copying is exactly identical to the one in the copy constructor. This is typical. In order to reduce duplicate code, the portion of the code that does the actual copying could be moved to a private member function that the copy constructor and overloaded assignment operator both call. Second, we’re returning *this so we can chain multiple assigments together:

If you need a refresher on chaining, we cover that in the section on overloading the I/O operators.

Finally, note that it is possible in C++ to do a self-assignment:

In these cases, the assignment operator doesn’t need to do anything (and if the class uses dynamic memory, it can be dangerous if it does). It is a good idea to do a check for self-assignment at the top of an overloaded assignment operator. Here is an example of how to do that:

Note that there is no need to check for self-assignment in a copy-constructor. This is because the copy constructor is only called when new objects are being constructed, and there is no way to assign a newly created object to itself in a way that calls to copy constructor.

Default memberwise copying

Just like other constructors, C++ will provide a default copy constructor if you do not provide one yourself. However, unlike other operators, C++ will provide a default assignment operator if you do not provide one yourself!

Because C++ does not know much about your class, the default copy constructor and default assignment operators it provides are very simple. They use a copying method known as a memberwise copy (also known as a shallow copy). We will talk more about shallow and deep copying in the next lesson.

9.12 -- Shallow vs. deep copying
Index
9.10 -- Overloading typecasts

35 comments to 9.11 — The copy constructor and overloading the assignment operator

  • panqnik

    I've written an article about copy constructor (and meaning of copy of object), you can read it on my blog, here:

    http://blog.szulak.org/dev/copy-constructor-and-copy-assignment/

  • aaishaa

    Hello,

    As you mentioned copy constructor is called when destination is NOT and already created object. However, in case of return value, If i save the function return value in an "already existing" object, i still calls copy constructor. Can you please clarify this?

    #include
    using namespace std;
    class Cents
    {
    public:
    int m_nCents;
    Cents(int nCents=0)
    {
    m_nCents = nCents;
    }

    Cents(const Cents &cSource)
    {
    m_nCents = cSource.m_nCents;
    cout << "in copy Constructor";
    }

    Cents returnObjectByVal()
    {
    Cents temp;
    temp.m_nCents=100;
    return temp;
    }
    };

    int main()
    {

    Cents obj1;
    Cents obj2;
    obj2= obj1.returnObjectByVal(); // COPY CONSTRUCTOR IS CALLED HERE, HOWEVER, IT SHOULDN'T AS OBJ2 IS aLREADY CREATED
    }

  • 1krishna23

    Hello,
    Class A
    {
    Private:
    Char name [10];
    Public:
    A (const A &obj);
    };
    For this copy constructor is
    A::A (const A &obj)
    {
    Strcpy (name, obj.name);
    }

    Class B {
    Private:
    Char name 1[10], name2, name3, name4…and so on …name1000;
    Public:
    B (const B &obj);
    }
    How can i Write a copy constructor for the class B with 1000 name as char variable,instead of declaring all variables in Class A

  • tunvir rahman tusher

    why my copy constructor is not calling when i am assigning t=t1+t2????

    ///////////////////////
    #include
    using namespace std;
    class test
    {
    int x,y;
    public:
    test(){x=0;y=0;}
    test(int i,int j){x=i;y=j;}
    test(test &ob){cout<x+ob.x;
    t.y=this->y+ob.y;
    return t;
    }
    int main()
    {
    test t,t1(1,2),t2(3,4);
    int x,y;
    t=t1+t2;/////i can't understand why test(test &ob) is not calling??
    t.get(x,y);
    t=t1;
    //test tx=t1;/////but this call copy constructor???
    t.get(x,y);
    cout<<y;
    getchar();
    }
    ///////////////////////

    thanks in advance

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">