TITLE: exception safe assignment operator (Newsgroups: comp.lang.c++, 23 Mar 99) HYSLOP: Jim Hyslop > [snip] > > > Always test for self-assignment in this operator. > > Test for self-assignment is not necessary (but can be a good > > optimization) in code that is exception safe. > > Read Guru of the Week #11 for all the gory > > details: http://www.peerdirect.com/resources/gotw011.html BROKVAM: "Roy Brokvam" wrote: > Am I forgetting something? What about member pointers to objects on the > heap? HYSLOP: Read the web page I refer to above. It answers your question. BROKVAM: > Consider (of course I wouldn't create my own class for an array of > int, so pls don't comment on that): HYSLOP: Well, you have to use *something* to illustrate your point, don't you :-) BROKVAM: > class Arrayofint { > public: > ... > Arrayofint& operator=( const Arrayofint& ); > ... > private: > int m_nelems; > int* m_elems; > }; > HYSLOP: [snip known-to-be-incorrect op=] BROKVAM: > I really need to encapsulate this in an "if ( this != &other )" > block, don't I? HYSLOP: Not if you do it right. OK, here goes - The Exception-Safe And Non-Self-Referential Copy Assignment Operator: Arrayofint& Arrayofint::operator=( const Arrayofint& other ) { int * tmp=new int[other.m_nelems]; // could throw std::copy(tmp, tmp+other.m_nelems, other.m_elems); // could throw // if we are using user-defined types // Now, by this point, all the dangerous work which can // throw exceptions has been complete, so we just clean up and // copy over: delete [] m_elems; // see notes after m_elems=tmp; // You're just assigning pointers - no possible exceptions m_nelems=other.m_nelems; // ditto return *this; // Done. } [ Jim Hyslop obviously forgot to use auto_ptr on the tmp pointer. Thanks to David Tribble and others for pointing this out. -adc ] Notice that there is no check for self-assignment. Notice also that copying is performed properly, and that nothing is leaked. Further, note that the assignment operator now has the benefit of being exception-safe. So, the rule is: If a copy assignment operator *must* test for self-assignment, it is not exception-safe. A copy assignment operator *may* test for self-assignment as an optimization (after all, you really don't want to go through and thrash the heap unnecessarily, do you?). Note: The above code assumes that the delete[] will not throw an exception. For a built-in type, that is obviously true. But, for a user-defined type, the rule is: Always write your dtor as if it has an exception specifier of "throw()", i.e. never allow an exception to propagate out of a dtor. Read the Guru of the Week at the above site - you won't regret it. Also watch for Herb Sutter's book which encapsulates GotW #1-40 and more.