|
Register or have you forgotten your password?
|
|
|
| Amiga OS -- Development This particular forum deals with issues regarding development for all versions of AmigaOS. |
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 | ||||||||
|
Energizer Bunny of Babble
![]()
Join Date: Feb 2002
Posts: 4,517
|
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 |
||||||||
|
|
|
|
|
#2 | ||||||||
|
Technoid
![]()
Join Date: Feb 2002
Posts: 214
|
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.
|
||||||||
|
|
|
|
|
#3 | |||||||||
|
Energizer Bunny of Babble
![]()
Join Date: Feb 2002
Posts: 4,517
|
Quote:
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 |
|||||||||
|
|
|
|
|
#4 | ||||||||
|
Kindred of Babble-on
![]()
Join Date: Feb 2002
Posts: 2,116
|
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 <reference.t> #include <hisclass.h> class MyClass : public HisClass { public: MyClass( ) { iGoToTheTopOfTheClass=new CheeseClass(); } static Reference<MyClass> createMyClass( ) { Reference<MyClass> 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.
|
||||||||
|
|
|
|
|
#5 | ||||||||
|
Beginner
![]()
Join Date: Feb 2002
Posts: 45
|
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 |
||||||||
|
|
|
|
|
#6 | |
|
Guest
Posts: n/a
|
Quote:
I suggest you do it this way. |
|
|
|
|
#7 | ||||||||
|
Beginner
![]()
|
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. |
||||||||
|
|
|
|
|
#8 | ||||||||
|
Kindred of Babble-on
![]()
Join Date: Feb 2002
Posts: 2,116
|
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<Void> 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<Void> 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.
|
||||||||
|
|
|
|
|
#9 | |||||||||
|
Sockologist
![]()
|
Quote:
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... |
|||||||||
|
|
|
|
|
#10 | |||||||||
|
Beginner
![]()
Join Date: Feb 2002
Posts: 45
|
Quote:
re Treke |
|||||||||
|
|
|
|
|
#12 | ||||||||
|
Energizer Bunny of Babble
![]()
Join Date: Feb 2002
Posts: 4,517
|
@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 |
||||||||
|
|
|
|
|
#13 | ||||||||
|
Energizer Bunny of Babble
![]()
Join Date: Feb 2002
Posts: 4,517
|
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 |
||||||||
|
|
|
|
|
#14 | ||||||||
|
Kindred of Babble-on
![]()
Join Date: Feb 2002
Posts: 2,116
|
"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.
|
||||||||
|
|
|
|
|
#15 | ||||||||
|
Kindred of Babble-on
![]()
Join Date: Feb 2002
Posts: 2,116
|
/************************************************** *************************
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 : <obscured>1998 copyright : <removed> email : <removed> ************************************************** *************************/ /************************************************** ************************* * * * 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 <assert.h> #ifdef WIN32 #include <malloc.h> #else #include <unistd.h> #endif #include <iostream.h> #include <typeinfo> #include <string.h> #ifndef NULL #define NULL 0x00000000 #endif // #define _CDEBUG_ 1 //-------------------------------------------------------------------- template <class T> 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<T> ptr) { return _ref == ptr._ref; } bool operator != (Reference<T> 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<T> 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 <class T> unsigned long Reference<T>::gBytesCount=0; template <class T> unsigned long Reference<T>::gFreedCount=0; #endif #endif
__________________
Hate figure.
|
||||||||
|
|
|
![]() |
| Bookmarks |
| Tags |
| c++ , constructors , question |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Blizzard 1260 memory type question/SCSI DVD-Rom question | HardStep | Amiga Hardware Issues and discussion | 0 | 10-29-2005 01:36 PM |
| Amiga crystal oscillator question (pinout question) | redrumloa | Amiga Hardware Issues and discussion | 2 | 07-29-2004 01:39 PM |
| A4000 simm question, MPEGA question | tormedhammaren | Amiga Hardware Issues and discussion | 8 | 05-11-2003 12:54 PM |