From: pjl@sparc10.cs.uiuc.edu (Paul Lucas)
Newsgroups: comp.lang.c++
Subject: Re: Default assignment semantics
Date: 14 Sep 92 15:20:55 GMT
Distribution: usa
Organization: University of Illinois at Urbana-Champaign

In <BuJs8K.Hzr@vcd.hp.com> John Matthews <jm@vcd.hp.com> writes:

>As I understand it, if a class does not have an explicitly defined
>assignment operator, a default assignment operator is generated
>by the compiler. This default operator simply does a member-wise
>assignment. As has been pointed out many times, these semantics
>are dangerous for classes that have pointers to dynamically created
>objects as fields.

*****>	What many people seem to have forgotten is that this is not a
	new problem.  Assigning good ol' structures in C that contain
	pointers is just as bad.  One has to write a copy function in
	such cases because the default assignment doesn't work.

>It seems to me that a more robust default assignment operator would
>have the following semantics:

>  1) Invoke the destructor of the object being assigned to.
>  2) Invoke the copy constructor on the object being assigned
>      to, taking as an argument the object being assigned from.

>In the case where a class has no user defined destructor or copy
>constructor, the above semantics devolves to member-wise
>assignment, just as before. However, for classes that have
>user defined destructors and copy constructors, (as all classes
>that have pointers to dynamic objects should) the above
>semantics generates code that is much safer. Take for example a
>String class, whose constructor allocates a character buffer for
>a string, and whose destructor frees that buffer. The user-defined
>copy constructor would construct its String object with a separately
>allocated character buffer of the same size as its String argument,
>and perform a string copy between the two character buffers.

*****>	Ah, but in some String classes, if the LHS's buffer is big
	enough to contain the RHS's, then the buffer is not
	deallocated.  BTW, some String classes use chunks of buffers of
	a rounded-off size to lessen fragmentation.

	Also, chances are that someone who's writing a full-blown string
	class won't forget to overload assignment; it's code is trivial
	and is dwarfed by the remaining code.

>Under the current default assignment operator semantics, for every  
>String assignment made, a character buffer is 'leaked', and two
>pointers to the same buffer are made.

*****>	Not if the assignment operator is overloaded.

>Under the above semantics,
>however, the assignee String first has its buffer deallocated, and
>then recieves a new buffer from the copy constructor, just like you
>would expect.

>Since this is not the semantics of the current assignment operator,
>a user defined assignment operator needs to be defined whenever
>a user defined destructor or copy constructor exists for a class.

*****>	Trivial.

>Thus what I want to do in most of my assignment operators is
>explicitly invoke the corresponding destructor and copy constructor.

*****>	Ah..."most."  There are occasions, as I've already pointed out,
	when one doesn't want the d'tor called.  To have this
	flexibility is probably part of the reason the assignment
	operator is as it is.

>I know how to explicitly call a destructor on an object, but how do
>you explicitly call a copy constructor on what used to be an object?
>The only way I know of to do this is to overload operator new() with a
>pointer argument. The overloaded new() operator would just return
>the pointer. I could then write an assignment operator like the following
>for any class X:

>        X& X::operator=( const X& from )
>        {
>                  this->~X();                                   // invoke
>destructor.
>                  new(this) X(from);                       // invoke copy
>constructor.
>                  return( *this );
>        }

>However overloading new seems a little kludgy when all I want to
>do is call a constructor on a specific object reference.

*****>	Well, it still seems simpler to just overload the assigment
	operator.

	Another case that comes to mind if reference-counting;
	assignment operators for such classes do different things
	altogether.
-- 
	- Paul J. Lucas				University of Illinois	
	  AT&T Bell Laboratories		at Urbana-Champaign
	  Naperville, IL			pjl@cs.uiuc.edu
Newsgroups: comp.lang.c++