We should be very careful when dealing with assignment operators where self-assignment is expected, directly or indirectly. When you have complex system where the reference of an object traverses through out the modules and involves in many assignment operation.
Lets take some code implementation that illustrating this one:
class ClassWithResource {
enum {
ESize = 100
};
public:
ClassWithResource () : iStr(NULL) { }
ClassWithResource (const char* aStr) {
CopyString(aStr);
}
ClassWithResource (const ClassWithResource& aObj) {
CopyString(aObj.iStr);
}
ClassWithResource& operator= (const char* aStr) {
if(this->iStr != aStr) {
delete [] iStr;
CopyString(aStr);
}
return *this;
}
ClassWithResource& operator= (const ClassWithResource& aObj) {
if( this != &aObj) {
delete [] iStr;
CopyString(aObj.iStr);
}
return *this;
}
~ClassWithResource() {
delete [] iStr;
}
void Display() {
cout<<"String is : "<<iStr<<endl;
}
private:
void CopyString(const char* aStr) {
iStr = new char [ESize];
strcpy(iStr, aStr);
}
private:
char* iStr;
};
In the code above, see the implementation of the assignment operators. Before copying the data, I am checking whether source and destination pointers are same. If we ignore that condition, then if there is self-assignment some where in the code, then we may delete own data and try to copy it, which does not exist at all! And the program will CRASH at this point.
Notice that, this checking is not required for copy constructer because there won't be any instance where you will send the same object (which is not constructed yet) to construct it.