The programmer who creates the class needs to make sure self-assessment is harmless. The simplest way to make sure that self-assignment is harmless is to perform an if test such as the one shown in the following example. #include <new> using namespace std; Fred& Fred::operator= (const Fred& f) throw(bad_alloc) { if (this == &f) <-- 1 return *this; // ... }
Self-assignment can also be rendered harmless by efficiency considerations. For example, the following assignment operator replaces the allocated memory only if the old allocation is too small to handle the new state. In this class, self-assignment would automatically be handled since it would skip the allocate/deallocate steps: #include <new> #include <iostream> #include <cstring> using namespace std; class String { public: String() throw(bad_alloc); String(const char* s) throw(bad_alloc); String(const String& s) throw(bad_alloc); ~String() throw(); String& operator= (const String& s) throw(bad_alloc); protected: unsigned len_; char* data_; }; String& String::operator= (const String& s) throw(bad_alloc) { if (s.len_ > len_) { <-- 1 char* newData = new char[s.len_+1]; delete[] data_; data_ = newData; } memcpy(data_, s.data_, s.len_+1); len_ = s.len_; return *this; }
The goal is to make self-assignment harmless, not to make it fast. It doesn't make sense to optimize self-assignment since self-assignment is rare. For example, when self-assignment actually occurs, the assignment operator would unnecessarily call memcpy(). Although that call could be removed by an extra if test, the extra if test would put more overhead on the normal path in an attempt to optimize the pathological case. So in this case the right trade-off is to avoid the extra if test and put up with an unnecessary memcpy() in the case of self-assignment. |