Welcome, Guest. Please login or register.

Author Topic: question about C++ constructors  (Read 10085 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline GlaucusTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 4518
    • Show only replies by Glaucus
    • http://members.shaw.ca/mveroukis/
question about C++ constructors
« on: January 23, 2003, 09:42:41 PM »
Hey,

So I have this class which allocates a bunch of stuff in a constructor.  Now, let's say one of those allocations fails, what's the best way to gracefully back out of this?  Should I throw an exception?  But this would require every time an object is allocated to be surrounded by a try{}catch block.  How would this work with statically allocated classes?!?  Seems like this isn't the best way to do this.  I can't think of any better way which makes me think that perhaps it's a bad idea to allocate resources that might fail in a constructor.  Opinions?!?

  - Mike
YOU ARE NOT IMMUNE
 

Offline Casper

  • Full Member
  • ***
  • Join Date: Feb 2002
  • Posts: 214
    • Show only replies by Casper
Re: question about C++ constructors
« Reply #1 on: January 23, 2003, 10:07:44 PM »
There is a saying when it comes to good programming: Allocate late, release early, i.e. you should allocate resources when you need them and release them as soon as possible.  You should not allocate stuff in the constructor unless you absolutely have to.
 

Offline GlaucusTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 4518
    • Show only replies by Glaucus
    • http://members.shaw.ca/mveroukis/
Re: question about C++ constructors
« Reply #2 on: January 23, 2003, 10:36:28 PM »
Quote
There is a saying when it comes to good programming: Allocate late, release early, i.e. you should allocate resources when you need them and release them as soon as possible. You should not allocate stuff in the constructor unless you absolutely have to.

Thanks for the reply.

My plan was to create a class that opens a group of windows.  The windows all get used together, I just wanted one single class to control them all as they would be acted upon as one entity.  These windows kinda need to be around so I can't use that principle.  However, I might just make a special method to open the windows and one to close them.

  - Mike
YOU ARE NOT IMMUNE
 

Offline DaveP

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2116
    • Show only replies by DaveP
Re: question about C++ constructors
« Reply #3 on: January 24, 2003, 07:48:58 AM »
Mike

I think you should seriously consider - where possible - using auto or smart points during memory allocation.

Firstly I would never throw an exception in a constructor.

What would be better would be to use a static method on the class to be the factory for the object, this then has permission to inspect the interior of the class to see that all allocations have gone well - as well as being the right place to throw an exception.

#include
#include

class MyClass : public HisClass
{
 public:
       MyClass( )
       {
            iGoToTheTopOfTheClass=new CheeseClass();
       }

       static Reference createMyClass( )
       {
               Reference cReturnable=new MyClass( );
               if ( cReturnable->iGoToTheTopOfTheClass==NULL )
                      throw new HolyMackeralsBatmanException( );

              return returnable;
       }
 
private:
    Reference< CheeseClass> iGoToTheTopOfTheClass; // autopointer template called Reference
};

Because the autopointer goes out of scope as soon
as the stack unwindes it deletes the MyClass instance which causes the iGoToTeTopOfTheClass autopointer to go out of scope.

The autopointer for  iGoToTheTopOfTheClass will check the contents of memory itself and see that it doesn't need to deallocate that.

By doing it this way not only do you need to worry about deallocation during a stack unwind or the messy business of supporting exception throwing on a constructor but you have nicely introduced yourself to the concepts of "Homes" and "Factories" for object instances so beloved of Distributed OO.
Hate figure. :lol:
 

Offline Treke

  • Newbie
  • *
  • Join Date: Feb 2002
  • Posts: 45
    • Show only replies by Treke
Re: question about C++ constructors
« Reply #4 on: January 24, 2003, 08:47:32 AM »
Or you can do something like that. (another proposal ) Ctor:

MayClass :: MyClass ()
                    : blValidityFlag ( true )
{
  try
      {
      //Allocate, instantiate stuff
       }
   catch (/*whatever you want to catch*/)
       {
       validityFlag = false;
       }
}

// public method, can be implemented also throwing
// exception
MyClass :: IsValid ()
  {
  return validityFlag;
  }

// then after constructor you can call a IsValid method
// if its not valid you can propagate and exception
// of coruse the best is to do a class which
// implements only Isvalid and derive your class from
// Something like IValidable interface ;)))

// So the usage can be

MyClass instance;
instance.Isvalid (); //can throw exception or return
                                   //false

There are, I guess (I am sure) more another posibilities. The goal is to be allways informed what failed, and and have the track of your "error source", "error flow" ....

re

Treke
 

  • Guest
Re: question about C++ constructors
« Reply #5 on: January 24, 2003, 09:19:37 AM »
Quote

However, I might just make a special method to open the windows and one to close them.

The idea of speacial methods is reasonable. You then might even open/close the windows without creating/destroying the handler object.
I suggest you do it this way.

 

Offline jack

  • Newbie
  • *
  • Join Date: Feb 2002
  • Posts: 41
    • Show only replies by jack
Re: question about C++ constructors
« Reply #6 on: January 24, 2003, 09:31:38 AM »
If u really have to allocate stuff in constructor, the best way is to build your own class which acts like the one you want to allocate. Make it(the new class) deallocate the stuff allocated by itself  in destructor. You can even add copy constructors, = operator etc (don't forget to use deep copy when implementing "=") . You will end with your own memory manager, little preformance loss, but it will prevent memory leaks. If you want example - let me know.


Jack.
 

Offline DaveP

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2116
    • Show only replies by DaveP
Re: question about C++ constructors
« Reply #7 on: January 24, 2003, 09:36:24 AM »
Ive done a more generic method than this in the past for
memory pointers to system objects. The Void object contains a pointer
to a memory are or NULL, the application writer uses Reference
smart pointer templates during normal use.

For memory that you own at a given point you call the Void.own( )
method ( and then when the reference count reaches zero the memory
is delete-d ) and if you decide you no longer own it you can call
Void.disown( ) and the pointer will still be valid but will no
longer assume that it needs to be cleared up when the Void( )
destructor is called by the Reference reference count
getting to zero.

Then anything specific that the application does not always
own  is a specialisation ( like a Window class ) of that Void class.

Pick and choose from the methods or even invent your own. Thankfully
we might not have freedoms as we used to but we certainly have
freedom in programming style.
Hate figure. :lol:
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: question about C++ constructors
« Reply #8 on: January 24, 2003, 10:48:59 AM »
Quote

DaveP wrote:
...
By doing it this way not only do you need to worry about deallocation during a stack unwind or the messy business of supporting exception throwing on a constructor but you have nicely introduced yourself to the concepts of "Homes" and "Factories" for object instances so beloved of Distributed OO.


Also, factories are very well worth a look because of a very cool feature that everbody getting into OOP craves at some point - the 'virtual' constructor. In reality, a virtual constructor is impossible since the compiler must know the exact object to be instansiated.
However, A factory can take a pointer to an existing polymorphic object and return a pointer to a new instance of the same class (usually via some virtual function magic).
There are several ways of doing this, I found that the method described in Bjaarne Stroustrup's 'The C++ Programming Language' 3rd Ed. works for me...
int p; // A
 

Offline Treke

  • Newbie
  • *
  • Join Date: Feb 2002
  • Posts: 45
    • Show only replies by Treke
Re: question about C++ constructors
« Reply #9 on: January 24, 2003, 12:03:51 PM »
Quote
found that the method described in Bjaarne Stroustrup's 'The C++ Programming Language' 3rd Ed. works for me...


Probably the best book is Design patterns by Gamma, Helm,Johnson and vlissides. The issue (why, how, and so on..)is called creational patterns (ie Abstract factory, Factory method. prototype.... )

re
Treke
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16867
  • Country: gb
  • Thanked: 4 times
    • Show only replies by Karlos
Re: question about C++ constructors
« Reply #10 on: January 24, 2003, 03:15:20 PM »
@Treke

Thanks. Looks interesting, I'll give it a look.
int p; // A
 

Offline GlaucusTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 4518
    • Show only replies by Glaucus
    • http://members.shaw.ca/mveroukis/
Re: question about C++ constructors
« Reply #11 on: January 24, 2003, 11:16:33 PM »
@Dave,

your comments on smart/auto pointers via the Reference template is very interesting.  let me see if I got it straight.

By using your Reference template you can dynamically allocate classes and be assured that when the reference goes out of scope the referenced class will then be deallocated - assuming there was only one reference to begin with.  I assume the destructor for the Reference template class would delete the wrapped object?  Is this correct???  Can I have the source to this? It might more sense if I just look at the code.

As for Design Patters, I think I need to pick up a copy.  Although I have Bjarne Stroustrup's C++ book it's the 2nd edition and doesn't mention Factories or other patterns.  I did however find some info on factories and the Signleton pattern and it might be useful to me.  The singleton pattern makes sense as I'll be opening a set of windows and there will never be more instances of these windows open.  They will also be global, the only problem is I'm not sure how to make it automatically deallocate itself in C++.  Anyway, I'll have to check out that book and see what it has to offer.  Off to Chapters I go!  :-)

  - Mike
YOU ARE NOT IMMUNE
 

Offline GlaucusTopic starter

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 4518
    • Show only replies by Glaucus
    • http://members.shaw.ca/mveroukis/
Re: question about C++ constructors
« Reply #12 on: January 24, 2003, 11:17:52 PM »
Oh btw, I'm using SAS C 6.57 which means I can't use templates.  :-(  So I may not be able to use your code directly but I would still like to look at the code for my own educational purposes.  :-)

  - Mike
YOU ARE NOT IMMUNE
 

Offline DaveP

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2116
    • Show only replies by DaveP
Re: question about C++ constructors
« Reply #13 on: January 25, 2003, 11:26:31 AM »
"By using your Reference template you can dynamically allocate classes and be assured that when the reference goes out of scope the referenced class will then be deallocated - assuming there was only one reference to begin with."

Correct, with the caveat that reference counting is 1-1 with the object instance so multiple references can exist and the last reference to go out of scope will be the one that deletes the object - unless you force the reference count to increment ( which I have
had to make provision for because VissyC does not handle C linkage function pointers with classes properly ).

" I assume the destructor for the Reference template class would delete the wrapped object? Is this correct???"
If it is the last one out.

" Can I have the source to this? It might more sense if I just look at the code."

yep. Ill post it in a bit when I make sure there are no confidential bits left, and Ill throw in a GPL statement.

Note that the style I use some don't like because it requires provision that the objects that it reference to implement a few methods :- incref, decref, clone ( for deep copy cloning ) and equals ( for value types ).

My top level superclass is called Object which if you really care what it does I will put under GPL and post here too.

Back in a mo....
Hate figure. :lol:
 

Offline DaveP

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 2116
    • Show only replies by DaveP
Re: question about C++ constructors
« Reply #14 on: January 25, 2003, 11:30:59 AM »
/***************************************************************************
                          reference.t  -  Reference is a template class
                    that allows C++ to manage references to classes
                    as a smart pointer might, detecting when a reference
                    is destroyed and decrementing the reference count
                    on the instance. Once the reference count reaches
                    zero then the memory is cleaned up.
 
   warnings          : Crippled, reference count can wrap in certain C++ semantic conditions.
                             -------------------
    begin                :  1998
    copyright         :  
    email                :
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef  POINTER_HEADER_
#define POINTER_HEADER_

#include
#ifdef WIN32
#include
#else
#include
#endif
#include
#include
#include

#ifndef NULL
#define NULL 0x00000000
#endif

// #define _CDEBUG_ 1

//--------------------------------------------------------------------

template class Reference
{
//   Constructors and destructor

public:
Reference() : _ref(NULL) { }
Reference(T* ptr_) : _ref(ptr_) { IncrRefCount(); }
Reference(void * ptr_) : _ref((T*)ptr_)
     { if ( _ref!=NULL) IncrRefCount(); }
  Reference( const Reference &other )
  { _ref=other._ref;
    if ( _ref!=NULL )
        IncrRefCount();
  }

   virtual ~Reference()
  {
    if ( _ref!=NULL )
      DecrRefCount();
  }
   Reference & operator = ( Reference ptr_ )
   {
        if ( _ref  != NULL )
            DecrRefCount( );

        _ref=ptr_._ref;
        if ( _ref!=NULL )
          IncrRefCount();
        return *this;
   }
   Reference & operator = (T* ptr_)
   {
        if ( _ref  != NULL )
            DecrRefCount( );
        _ref=ptr_;
        if ( _ref!=NULL )
          IncrRefCount();
        return *this;
   }
   T* operator -> () { assert(_ref!=NULL); return _ref; }
   T& operator * () { assert(_ref!=NULL); return *_ref; }
   operator T* () { assert(_ref!=NULL); return _ref; }

   bool operator == (Reference ptr) { return _ref == ptr._ref; }
   bool operator != (Reference ptr) { return _ref != ptr._ref; }
   bool operator == (T* ptr_) { return _ref == ptr_; }
   bool operator != (T* ptr_) { return _ref != ptr_; }

// Shallow copy cloning, to deep copy clone override
// the clone method on Object
   static T* clone( Reference ptr )
   {
         T* retval = (T*)malloc( sizeof(T) );
         memcpy(retval,ptr._ref,sizeof(T));
         retval->clone(ptr._ref);
         return retval;
   }
   bool const isNull() { return _ref == NULL; }
   long const getRefCount() { return _ref->refcount(); }
    T* getPointer() { return _ref; }
    T* recast() { return _ref; }
   T* getPointerForceIncref( ) { IncrRefCount(); return _ref; }
   
private:
   void IncrRefCount()
   {
        if ( _ref!=NULL )
        {
#ifdef _CDEBUG_
          gBytesCount=gBytesCount+sizeof(T);
#endif
          _ref->incref( );
        }
   }
   void DecrRefCount()
   {
        if ( _ref!=NULL )
        {
#ifdef _CDEBUG_
          gBytesCount=gBytesCount-sizeof(T);
#endif
          _ref->decref( );
          if ( _ref->refcount() == 0 )
          {
             // printf("%d->del()\n",_ref);
              _ref->mark_deleted( );

              delete _ref;
#ifdef _CDEBUG_
              gFreedCount=gFreedCount+sizeof(T);
              cerr << typeid(this).name()
                   << " Active bytes:" << gBytesCount
                   << " Freed bytes:" << gFreedCount << endl;
#endif
          }
          _ref = NULL;
        }
   }
#ifdef _CDEBUG_
   static unsigned long gBytesCount;
   static unsigned long gFreedCount;
#endif
private:
    T* _ref;
};

#ifdef _CDEBUG_
template
unsigned long Reference::gBytesCount=0;

template
unsigned long Reference::gFreedCount=0;
#endif


#endif
Hate figure. :lol: