TITLE: Constructors and operator = are very similar PROBLEM: ldup@ra.alcbel.be (Luc Duponcheel), Dec 2, 1991 [condensed] #include "new.h" class X { // ... X(const X &) ; // code depends on X ~X() ; // code depends on X X &operator=(const X &x){ if (this != x) { ~X() ; new (this) X(x) ; } return *this ; } // ... } ; Is this a good method for obtaining consistent semantics between X(const X &) and X &operator=(const X &)? Any (kind of) comments are welcome! RESPONSE: Harald Fuchs 1. Cute trick. 2. Maybe less efficient than a hand-coded assignment operator. Consider a class String containing a char* without delayed copying. The copy constructor would allocate it, the destructor would delete it. If the new String has the same length as the old one, you can simply reuse the allocated area. You miss chances for optimizations like that if you are too lazy to get your assignment operator right ;-) RESPONSE: Jamshid Afshar (jamshid@emx.utexas.edu) [deleted] An explicit destructor call must use `->' or `.' (ARM 12.4 p279) or else there would be confusion with the unary ~ operator. The above line should be: this->~X() ; new (this) X(x) ; I think the syntax requirements for explicitly calling a destructor mean that there is no way to override the virutalness of an explicit destructor call, right? BTW, BC++ 2.0 requires `this->X::~X()'. I haven't received BC++ 3.0 yet (another 1-2 weeks!) so I don't know whether Borland has fixed this. [deleted] I don't think it is a good method because it is dangerous when the destructor is virtual (as destructors usually should be -- see the FAQ). You must make sure that you define operator=() in all derived classes and that it doesn't call the base class's operator=(), otherwise you would get a destructor being called multiple times for the same object. Make sure your derived classes all define operator=() as: Derived& Derived::operator=(const Derived& other) { if (this != &other) { this->~Derived(); new (this) Derived(other); } } The attempt to reuse code is noble but I would suggest you instead define (maybe private) member functions like init(), clear() and copy(const X&) which are used by the constructors (they all call init() and copy-ctor also calls copy()), the destructor (calls clear()), and the assignment operator (calls copy() which calls clear()). Here's an example not intended for real-use: class EZString { // partial listing of very unoptimized string class public: EZString() { init(); } EZString(const EZString& other) { init(); copy(other); } ~EZString() { clear(); // do any dtor-specific cleanup } EZString& operator=(const EZString& other){ copy(other); return *this; } //... private: char* _s; void init() { // do whatever would be done in the default constructor _s = 0; } void clear() { // bring back to same state as if just used default-ctor delete [] _s; init(); } void copy(const EZString& other) { if (this!=&other) { clear(); if (other._s != 0) { _s = new char[strlen(other._s) + 1]; strcpy(_s, other._s); } } } }; What I like about approaches like this is that it makes the idea of member functions as object state-changers very explicit.