If you want to concatenate assignment like this
int x, y, z; x = y = z = 15;
The convention is to make the assignment operators return a reference to *this.
11 Handle assignmnet to self in operator =
You can easily assign an object to itself without knowing it
// Example 1 Foo *px, *py; px = py; //Example 2 a[i] = a[i];
It is dangerous to assign an object to self if your class doesn't handle this kind of opeator appropriately. Let's consider an example here:
class Bitmap{...}; class Widget { ... private: Bitmap *m_pb; }; Widget& Widget::operator=(const Widget& rhs) { delete m_pb; m_pb = new Widget(rhs); return *this; }
You will be dead if you assign an object to itself, beacause you will end up holding a pointer to a deleted object!
One way but not the best way to deal with self assignment is to write code to explicitly deal with this situation:
Widget& Widget::operator=(const Widget& rhs) { if(this == &rhs) { return *this; } delete m_pb; m_pb = new Bitmap(*rhs).m_ph; return *this; }
This is not the best way because above this operator is not exception-safe. What does that mean? Imagine what if an exception is thrown when
ph = new Bitmap(*rhs.m_ph)
is been executed(for example, not enough memory), then the object will hold a pointer to a deleted object.
Luckily, making operator= safe renders it self-assignmnet-sage, too. So, the best way to accomplish that is:
Widget& Widget::operator=(const Widget& rhs) { Bitmap* tmp = m_pb; pb = new Bitmap(*rhs.m_pb); delete tmp; return *this; }
Now if "new Bitmap" throw an exception, pb remains unchanged. Even without the identity test, this code handle assignment to self, because we make a copy of the original bitmap, point to the copy we made, and then delete the original Bitmap.
A more straightforward way to do so is to use exception-safe function swap
Widget& Widget::operator=(const Widget& ths) { Widget temp(ths); swap(temp); return *this; }