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;
}