C++ Constructors, Destructors
                            and
                      Default Methods

                            Bolo


Background

     Every C++ class has a minimum of 4 methods.  They exist
whether or not you create them.     The methods are:


 +---------------------------------------------------------+
 |What                  Name                               |
 +---------------------------------------------------------+
 |Default Constructor   A::A()                             |
 |Copy Constructor      A::A(const A &)                    |
 |Assignment            [const] A &A::operator=(const A &) |
 |Destructor            A::~A()                            |
 +---------------------------------------------------------+


     The default copy constructor and  assignment  construc-
tors are to do a bit-wise copy of any non-class members of a
class.  Whitespace (padding) between class  members  is  not
copied.   If  a  class  contains any other classes, then the
copy constructor or assignment constructor for that class is
used instead of the bit-wise copy.


Constructor and Assignment Necessities

     If a class contains a pointer, you must define your own
versions of them because the class is just an accident wait-
ing to happen.  The first time a default copy constructor or
assignment operator goes off, the  ownership  of  pointed-to
objects  becomes  questionable.   If  a  class SHOULD NOT BE
COPIED, then provide unimplimented, private  copy  construc-
tors and assignment operators.  At the language level people
won't be able to use those methods.  At the link level, any-
thing  that would generate an implicit call to those methods
won't be able to find them.

     Note that this does not mean that any class that uses a
class containing a pointer needs to define copy constructors
or assignment operators.  Because  the  language  implicitly
generates  calls  to copy constructors and assignment opera-
tors for any class members it will just work.

     If you  aren't  going  to  provide  or  disable  the  4
"always"  methods  for a class, don't define empty ones.  It
doesn't do you, me, or the compiler any good, and just  con-
fuses  things  if  you  try  to  use  a tool that identifies
classes missing copy constructors and assignment  operators.
Note there is one place you may want to have empty construc-
tors.  That is  to  expose  a  default  constructor  through
inheritance.  For example, an intermediate class that imple-
ments a virtual function but that is not used  itself.   For
example  you make a shim class B that inherits from class A.
You may need to copy all the A constructors  to  B  to  keep
them exposed so that a B can act like an A.

     Remember  that  if  you have any non-class member vari-
ables that you need to have at least a  default  constructor
to initialize those variables.

     A::A(const  A &) {} IS NOT A COPY CONSTRUCTOR.  It does
nothing at all.


Other Things

     C++ classes have colon, ":" initializers.  These should
be  used instead of assignments in the body of the construc-
tor methods.  Why?  Well, the compiler can help you  out  to
find  member  variables  that  are  not initialized, or that
might be initialized in an unexpected order.  It is the only
way  to  initialize const members.  By using the proper con-
structors for the  member  variable  classes  in  the  first
place,  you reduce execution overhead.  Only the proper con-
structor has to run, not the default  constructor  and  then
whatever assignment operator is needed.

     The  colon initializers should appear in the order that
member variables are declared.  That is the order  in  which
C++  initializes  member  variables, and good compilers will
give warnings if you try doing it in any other order,  since
the  will  reorder  the  initializations  to follow what the
standard says.

o    Don't provide an initializer  for  a  member  that  you
     aren't going to provide a value for.

o    DO  provide  an initial value for any C members.  These
     are the basic c/c++ non-class types such  as  pointers,
     integers, floats, bools, etc.

o    The  colon  initializer  should be in the first column,
     followed by a space and the name(value) initializer for
     the  first  member,  in  order,  to be initialized.  If
     there are more  initializers,  follow  the  initializer
     with a comma, and then start a new line, beginning with
     two spaces for the next initializers.

          A::A(int i, double d)
          : my_integer_value(i),
            my_real_value(d)
          {
          }

o    If you define any virtual methods in a class, you  must
     define  a  virtual  destructor.  If the top-level class
     where the virtual class starts at doesn't have anything
     to destruct, you must provide a null default destructor
     for it.
          class A {
               virtual ~A() { }
          };

o    In most cases the copy  constructor  should  initialize
     all  its  members to a known "null" state, and then use
     the assignment operator for the class to do the  actual
     assignment.  That guarantees that copy constructors and
     assignment  operators  are  identical  ...  which  they
     should  be.   There  are some cases which might require
     seperate implementations, but there should be  no  sur-
     prises if someone switches from using a declaration and
     an assignment to just using a copy constructor.

o    If a class inherits from another class,  remember  that
     you  need  to  run  the  copy constructor or assignment
     operator for the inherited-from classes as appropriate.
          class B : A {
               int  _i2;
          };
          B::B(const B &r)
          : A((const A &)r),
            _i2(r._i2)
          {
          }
          const B &B::operator=(const B &r)
          {
               *(A *)this = (const A &) r;
               _i2 = r._i2;
               return *this;
          }


Your Mission, Should You Choose to Accept It

     Is  to  go  through  your  portions of the Niagara code
base.  Identify classes that exhibit the above problems  and
omissions  and  fix  them.   If you find something you can't
fix, make a note of it for later in the source code as  well
as  to  other people.  That way another person won't stumble
across the problem and wonder about what is going on.   They
will find the comment and know, or perhaps know much earlier
in the game from the note.