Feb 10, 2012

C++ and overloading the assignment operator


I was reviewing a C++ course on Pluralsight to see if it would be a good teaching tool. I thought Kate Gregory did a really good job but she made some errors on her assignment operator so I dedicate this blog to her.

Overloading operator=

There are two problems with the overload. It doesn't check for assignment to self, and it's not exception safe. I don't really think this is nit-picking (I'll do that later), this is an important topic for students to understand. In The C++ Programming Language, Stroustrup(p 246 3rd edition) has one of his small comments that speaks volumes, it reads

// beware of self-assignment t=t.

Scott Meyer's also made made self assignment the topic of Item 17 in Effective C++ 2nd Edition. In Kate's example she has a pointer to a class named Resource and when assigning she wants to get a new class. She deletes the old pointer and then gets a new Resource. It looks like this:

delete pResource;

pResource = new Resource(p.pResource->GetName()): 

//where p is the parameter passed in to operator=

The problem is, if the user tried to assign a variable to itself, the first delete also deleted p.pResource and now a deleted pointer is being dereferenced. The quick fix is to just check for self assignment as the first line of the method and return:

if (*this == p) return *this;  //assumes operator == exists

Exception Safety

Even Stroustrup's sample isn't exception safe. Like Kate, he invokes delete first and then invokes new to get the copy. Unfortunately, if new throws there is no way to return the original object to the state it was in prior to the throw. The solution is a little messy; and another argument to bolster Kate's opinion that you should use modern smart pointers and avoid all this to begin with. Assuming reference counted semantics will work for your class when copying or assigning. In effect, to make this exception safe, you need to first make sure you can new up the required item and put it in a temporary variable. If that throws, handle it, and leave the original item unchanged. Sutter talks about this in depth in Exceptional C++ Item 9, and creates a handy helper class to hide some of the messiness and try/catch logic. I haven't read it yet, but it looks like in Effective C++ 3rd Edition Scott Meyer's rewrote item 17 and opts for taking a smart pointer approach.

A closing nit on std::endl

I also notice that Kate seems to prefer std::endl over "\n" and presents it as the equivalent. Andrei Alexandrescu once referred to this as the endl fiasco and I think it’s worth mentioning that std::endl also does a buffer flush and in some situations can have a negative performance impact.

About Me

My photo
Tod Gentille (@todgentille) is now a Curriculum Director for Pluralsight. He's been programming professionally since well before you were born and was a software consultant for most of his career. He's also a father, husband, drummer, and windsurfer. He wants to be a guitar player but he just hasn't got the chops for it.