Search

9.14 — Overloading the assignment operator

The assignment operator (operator=) is used to copy values from one object to another already existing object.

Assignment vs Copy constructor

The purpose of the copy constructor and the assignment operator are almost equivalent -- both copy one object to another. However, the copy constructor initializes new objects, whereas the assignment operator replaces the contents of existing 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 (note: this includes passing or returning objects by value).
  • If a new object does not have to be created before the copying can occur, the assignment operator is used.

Overloading the assignment operator

Overloading the assignment operator (operator=) is fairly straightforward, with one specific caveat that we’ll get to. The assignment operator must be overloaded as a member function.

This prints:

5/3

This should all be pretty straightforward by now. Our overloaded operator= returns *this, so that we can chain multiple assignments together:

Issues due to self-assignment

Here’s where things start to get a little more interesting. C++ allows self-assignment:

This will call f1.operator=(f1), and under the simplistic implementation above, all of the members will be assigned to themselves. In this particular example, the self-assignment causes each member to be assigned to itself, which has no overall impact, other than wasting time. In most cases, a self-assignment doesn’t need to do anything at all!

However, in cases where an assignment operator needs to dynamically assign memory, self-assignment can actually be dangerous:

First, run the program as it is. You’ll see that the program prints “Alex” as it should.

Now run the following program:

You’ll probably get garbage output (or a crash). What happened?

Consider what happens in the overloaded operator= when the implicit object AND the passed in parameter (str) are both variable alex. In this case, m_data is the same as str._m_data. The first thing that happens is that the function checks to see if the implicit object already has a string. If so, it needs to delete it, so we don’t end up with a memory leak. In this case, m_data is allocated, so the function deletes m_data. But str.m_data is pointing to the same address! This means that str.m_data is now a dangling pointer.

Later on, when we’re copying the data from str into our implicit object, we’re accessing dangling pointer str.m_data. That leaves us either copying garbage data or trying to access memory that our application no longer owns (crash).

Detecting and handling self-assignment

Fortunately, we can detect when self-assignment occurs. Here’s a better implementation of our overloaded operator= for the Fraction class:

By checking if our implicit object is the same as the one being passed in as a parameter, we can have our assignment operator just return immediately without doing any other work.

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 assignment operator

Unlike other operators, the compiler will provide a default public assignment operator for your class if you do not provide one. This assignment operator does memberwise assignment (which is essentially the same as the memberwise initialization that default copy constructors do).

Just like other constructors and operators, you can prevent assignments from being made by making your assignment operator private or using the delete keyword:

9.15 -- Shallow vs. deep copying
Index
9.13 -- Converting constructors, explicit, and delete

22 comments to 9.14 — Overloading the assignment operator

  • jinendra

    Why cant we overload assignment operator using a friend function.
    The operators (), [], -> and = can be overloaded only as class members; all other overloaded operators can (also) be implemented as friends

    • Alex

      If you could define operator= as a non-member, then that also means you could define the overridden operator= local to a file. That could lead to inconsistencies, where operator= used the default behavior everywhere except in that one file.

      Forcing operator= to be a member avoids this situation.

  • Tom

    Hello again Alex -

    I am having trouble grasping when and where to use *this. I will go back and re-read that chapter, but it occurs to me that it might help me (and others) if you had a symbolic diagram of the stack so I could clearly see what’s going on when *this is returned by a function.

    Thanks - this website is a great intro to C++.

    • “return *this” simply returns the object that the member function is working with to the caller.

      Thus, if you called:

      foo.someMemberFunction();

      and someMemberFunction() returned *this, someMemberFunction() would return foo.

      The hardest thing for most people seems to be just understanding what the this pointer is doing in the first place. The actual return mechanics are the same as with any other return value.

      • mslade

        This confused me for a bit, too, so I’ll offer my understanding that it might help someone else.

        Returning *this will dereference the “this” pointer, and instead return the actual object itself. What I got tripped up on is why it wasn’t thus creating a copy of this and returning that. The answer is because this function returns a Cents& (reference). As a result, the object is not copied and instead the capturing value gets the proper object.

  • kuldeep

    Hi Alex,

    This tutorial was really helpful, I’ve one doubt, is it necessary to have assignment operator ,if copy constructor is already present, if we are sure that we are not using any assignment ( only instantiating the new object from existing one, in this case only copy constructor is enough rt ? ), do we still need to overload assignment operator ?

    • No, it’s not required to have an assignment operator (if you don’t create one, the compiler will create one for you and it will do a shallow copy). However, this is generally a bad idea because when you look at your code in 3 months you’re likely to forget you didn’t overload the assignment operator and then when you try and use it, you won’t get the results you expect.

  • Joris

    Can you explain how self-assignments can show up in realistic code? Could they be auto-generated somehow?

    I feel maybe an assert should be appropriate if it is a real issue to get rid of them :-/

    • Self-assignments aren’t common (particularly in string classes) but it is possible to inadvertently get them in other cases (I can’t think of any good examples).

      There’s really no reason for a self-assignment to fail. The generally-intended end-result of the following statement:

      is that “a” should equal whatever it did before this statement (unless you overloaded operator= to do something weird, like reference counting).

      So we just special-case the self-assignment case and go on with life. 🙂

  • dmanniteaux

    Hi Alex,

    Can you explain further why in the code:

    Cents& operator= (const Cents &cSource);

    We require operator= to be passed by reference?

    I am assuming it’s similar to the explanation of ” .. Second, the parameter MUST be passed by reference, and not by value. Can you figure out why?” for the copy constructor part but it would be helpful if you could go into the same detail with this case as well so I can understand 🙂

    Thanks!!

  • Peter

    Hi Alex,

    Why does the code below work without the overloaded operator=?

    how is that differ from

    main.cpp

    Hand.h

    Hand.cpp

    • Alex

      This is an initialization, so operator= wouldn’t be called. Here’s what happens:
      1) peter + wendy is evaluated first.
      2) You’ve overloaded operator+ to cause peter + wendy to return an object of type Hand.
      3) Object two is then constructed (using the copy constructor) with the object returned from operator+ as the argument.

      • Peter

        Thank you!
        I really like your comprehensive quizzes because they really help me review what I’ve learned. Since you don’t have the comprehensive quiz for chapter 9 or 10, I have been working on extending the blackjack example from before.  

        I was wondering if you wouldn’t mind taking a look at my code and comment on it especially errors in logic? (Once I’m done with it that is)

        It is more than a few hundred lines long and several files so I don’t think it would be appropriate to post it on here. What would be an appropriate way to get my program to you?

        Either way I very much appreciate all of this!

        • Alex

          Drop me a line via the comment form in the About / Contact section.

          • Peter

            Hey Alex,

            I’m done with the blackjack example.  I dropped you a line via the comment form a while back but haven’t heard from you.  Was wondering if you still would want to take a look?

            • Alex

              Hey Peter,

              I’ve been slammed in real life, and have barely had time to respond to the comments here. I’ll try to look at your code soon but I’m not sure when I’ll be able to get to it. Sorry. 🙁

              • Peter

                No problem!
                I completely understand.  When you do have sometime and willing, can you send me an email and i’ll get my code to you?
                Thank you very much!

  • Vijay

    I think this operator overloading chapter needs one more article "overloading new and delete operator". It would be great, if we throw some light on it.

    • Alex

      Thanks for the thought! Overloading new and delete is more of an advanced topic. Would be fun to explore that one some day, but most people don’t write their own allocators (and the ones that do probably aren’t going to come here to learn how to do so). 🙂

  • damiano

    Hi,
    In

    shouldn’t you use delete[] operator instead? Thanks

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter