* (e-mail address removed):
Hi Everyone,
I was just wondering, about the overloaded assignment operator for
user defined objects. It is used to make sure that the following works
properly,
obj1 = obj;
so the overloaded operator function performs the necessary copy of
obj's member in to obj1. Can't the same be done using copy
constructor? If so, then what is the difference between both the
mechanisms.
Ah, good question.
First, about the difference. A constructor is used to convert raw and
possibly random bits to a valid instance. An assignment operator is
used to change the value of an existing instance, and that might entail
deallocating storage that the existing instance has a pointer to.
E.g., consider -- while disregarding optimizations --
std::string s( "blah blah" ); // Constructor, allocates storage.
s = "Foo bar"; // Assignment, deallocates + allocates new storage.
The constructor can't make any assumptions about the raw storage it's
handed, and in particular it can't assume that there's a valid pointer
in there. The assignment operator, on the other hand, must make such
assumptions, depending on the type. Conceptually the assignment
operator has to do the job of first destructing the current object and
then copy constructing a new object.
First, positive, this thinking means it's simply Wrong(TM) to express
construction in terms of assignment: it's positive because it's so easy
to see that anyone can grok it when pointed out, that assignment is
/more/ than construction, therefore, construction should not be
expressed in terms of assignment. Yet some professionals (in the sense
of being paid by an employer) have done that, and even imposed it on
others by making it part of some in-house architecture or overall
application design. It's an easy trap to fall into when your experience
is primarily with some other language where that makes sense, but in C++
it leads to horribly complicated and bug-ridden code, so don't do it.
Negative, this thinking leads naturally to a Very Dangerous(TM) way of
expressing assignment in terms of destruction and construction, which
seems to be rediscovered by every programmer learning C++:
MyType& operator=( MyType const& other )
{
this->MyType::~MyType(); // Destruct, leaving raw bits.
::new( this ) ( other ); // In-place copy construct.
return *this;
}
One reason it's very dangerous is that the copy construction just may
fail, throwing an exception, and in that case the current instance has
already been destructed, oops. Another reason it's very dangerous is
that when this operator is called on an object of a type derived from
MyType, it changes the the dynamic type of the object (oops)! Which
means it effectively imposes a requirement on derived classes to not
call MyType's copy assignment operator, on pain of Undefined Behavior,
without that requirement being enforced by the compiler.
However, while the above is Very Dangerous, it leads in just two small
steps to the common idiom for implementing assignment in terms of copy
construction. Namely, instead of destructing the current instance, copy
construct into a completely new instance, and then /swap/ the contents
with the current instance. This requires a swap operation for the type:
MyType& operator=( MyType const& other )
{
MyType temporary( other ); // Copy construct into new instance.
swap( other ); // Swap contents with new instance.
}
Here, when the temporary goes out of scope it's destructed in the normal
way, deallocating any buffers etc. that the current instance may have
had, now (after the swap) managed by the temporary.
If swap and the destructor provide the no-throw exception guarantee,
then this is also exception safe.
And the code can be further simplified (the second step) to just
MyType& operator=( MyType other )
{
swap( other );
}
Which is the common idiom. It's not always the best way to implement
assignment. But in the absence of strong reasons not to do it this way,
it should be your default implementation: always, if practical (and
since the code is so simple it's nearly always practical) implement
assignment in terms of copy construction, swap and destruction.
Cheers, and hth.,
- Alf