[comp.lang.c++] Destructors and new

dmg@ssc-vax.UUCP (David Geary) (05/31/89)

  I need some help.  In the process of learning C++ for use on a project,
I am developing some "basic" classes.  First of all, I developed a string
class, and then I went on to developing a "list" class.  I've included some
of the code from my .hxx file:

//////////////////////////////////////////////////////////////////////////////
//  LISTCLASS.HXX:                                                          //
//                                                                          //
//  This file defines three objects:                                        //
//                                                                          //
//  I    Class link:                                                        //
//                                                                          //
//       links are primitive objects which have only a constructor and the  //
//       ability to print out the information contained in them.  Each      //
//       link has next and prev(ious) pointers which point to other         //
//       links in a list.                                                   //
//                                                                          //
//  II   Class list:                                                        //
//                                                                          //
//       lists are objects which manage a list of links.  Each list         //
//       contains pointers to the first and last links in the list, and     //
//       also a count of the total number of links in the list at any       //
//       given time.  lists have the ability to insert links, get links     //
//       from the list, or unlink links from the list.  A list can also     //
//       print information about itself, or show info on each of the        //
//       links in the list.                                                 //
//                                                                          //
//       lists have the following operators overloaded:                     //
//                                                                          //
//   +=      Given a pointer to a link, the link is appended to the list.   //
//                                                                          //
//   +=      Given a reference to a link, the link is appended to the list. //
//                                                                          //
//   --       Chops the last link off the node (unlinks it).  Note          //
//                That a pointer to the link removed is returned.           //
//                                                                          //
//   []       Returns a reference to a specified link (as though the        //
//                list were an array).                                      //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#ifndef LIST_CLASS
#define LIST_CLASS

//=============================== Class link ===============================//

class link
{                            
  friend class list;              // A list can access private parts of a link.
  friend class list_iterator;     // list_iterators need to access links too.

  link  *next;                    // The next link in the list.
  link  *prev;                    // The previous link in the list.

  public: 

  link() { prev = next = NULL; }  // Constructor:  link x;

  virtual void print() 
  { 
    cout << form("Addr = %ld\nNext = %ld\nPrev = %ld\n\n", this,next,prev); 
  }               
};

//=============================== Class list ===============================//

class list
{ 
  friend class list_iterator;  // a list_iterator can access list's privates.

  protected:
 
  int    num_links;            // num links on list at any given time.
  link*  first;                // first link on list.
  link*  last;                 // last link on list.
 
  public:
 
  list() { num_links = 0, first = last = (link*)NULL; }

  BOOLEAN insert     (link& lnk, int pos);  // Insert lnk at pos in list.
  link*    getp      (int pos);             // Get Pointer to specified link.
  link&    getr      (int pos);             // Get Reference to spec. link.
  link*    unlink    (int pos);             // Unlink specified link.
  void     shownodes ();                    // Print link info for links.

  virtual void print ();                    // Prints private data of list.       

  BOOLEAN list::operator+=(link& lnk)  { return insert(lnk,num_links+1);  }
  BOOLEAN list::operator+=(link* lnk)  { return insert(*lnk,num_links+1); }
  link*   list::operator--()           { return unlink(num_links);        }
  link&   list::operator[](int pos)    { return getr(pos+1);              }
};

#endif


  Ok?  So then, any instance of a class which is derived from link can be
used as a link, and appended to a list:

class string : public link
{
  //  a bunch of stuff...
};

main()
{
  list     mylist;
  string   s1, s2, s3;

  mylist += s1;
  mylist += s2;
  mylist += s3;

  mylist.print();
  mylist.shownodes();
}

  This works just fine.  However (finally getting to the problem), I'd like
to be able to have a list of dynamically allocated links, so I derived the
following class from list:

class dlist : public list    // "dynamic" list...
{
  public:

  dlist() { num_links = 0; first = last = (link*) NULL; }
 ~dlist() { int i=num_links; while(i-- >= 0) delete getp(i); }
};

  Now I can do things like:

class string : public link
{
  // same bunch of stuff as above...
};

main()
{
  dlist  my_dlist;

  my_dlist += new string;
  my_dlist += new string;
  my_dlist += new string;

  my_dlist.print();
  my_dlist.shownodes();
}

  Ok, this works too - sort of.  The problem is that in the example using
a "list", the destructors for s1, s2 and s3 are called.  However, in
the example using "dlist", no destructors are called for the instances
of strings that get appended onto the list.  Notice that the dlist destructor
calls delete to free the memory associated with each string, but the 
explicit destructor for strings is not called.

  Any suggestions?

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ David Geary, Boeing Aerospace, Seattle                 ~ 
~ "I wish I lived where it *only* rains 364 days a year" ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

vasta@apollo.COM (John Vasta) (06/03/89)

In article <2685@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
>
>  I need some help.  In the process of learning C++ for use on a project,
>I am developing some "basic" classes.  First of all, I developed a string
>class, and then I went on to developing a "list" class.  I've included some
>of the code from my .hxx file:
>
>  [code example deleted]
>
>  Ok, this works too - sort of.  The problem is that in the example using
>a "list", the destructors for s1, s2 and s3 are called.  However, in
>the example using "dlist", no destructors are called for the instances
>of strings that get appended onto the list.  Notice that the dlist destructor
>calls delete to free the memory associated with each string, but the 
>explicit destructor for strings is not called.
>
>  Any suggestions?

Sounds like you've tuned in recently - you may have missed the big
virtual destructor discussion. Yes, destructors can be declared virtual
(in recent implementations, at least). Your dlist destructor only knows
that it's destroying an object pointed to by a link*, and the link class
has no destructor, so there's nothing to do. Declare a virtual destructor
in the link class, and then classes derived from link will have their
destructors called when deleting via a ptr-to-link.

-- 
John Vasta                Apollo Computer, Inc.
vasta@apollo.com          M.S. CHA-01-LT
(508) 256-6600 x6362      330 Billerica Road, Chelmsford, MA 01824
UUCP: {decwrl!decvax, mit-eddie, attunix}!apollo!vasta