another preference question....
-
Leslie Sanford wrote:
Instead, I must remember to call Dispose where it is implemented.
Not really needed if the object does not consumes lots of memory...
Dispose
/Finalize
is invoked automatically (but not necessarily immediately) when the instance goes out of scope.If you truly believe you need to pick a mobile phone that "says something" about your personality, don't bother. You don't have a personality. A mental illness, maybe - but not a personality. - Charlie Brooker My Blog - My Photos - ScrewTurn Wiki
Dario Solera wrote:
Dispose/Finalize is invoked automatically (but not necessarily immediately) when the instance goes out of scope.
I don't think
Dispose
is invoked automatically. I know the finalizer is, but by the time it's invoked, you can't count on any of the references in your object as still being valid. They may have already been collected. You can release unmanaged resources (which is important), but that's about it. -
Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
I'm sure we can invent reasons to do it their way but in everyday coding at a business logic level I really do think an instance should be initialised to a common state on construction. Code runs in all manner of environments and they are not all equal. Rather have your code set the playing field than the environment.
regards, Paul Watson Ireland & South Africa
Shog9 wrote:
And with that, Paul closed his browser, sipped his herbal tea, fixed the flower in his hair, and smiled brightly at the multitude of cute, furry animals flocking around the grassy hillside where he sat coding Ruby on his Mac...
-
Dario Solera wrote:
Dispose/Finalize is invoked automatically (but not necessarily immediately) when the instance goes out of scope.
I don't think
Dispose
is invoked automatically. I know the finalizer is, but by the time it's invoked, you can't count on any of the references in your object as still being valid. They may have already been collected. You can release unmanaged resources (which is important), but that's about it.Leslie Sanford wrote:
I don't think Dispose is invoked automatically. I know the finalizer is, but by the time it's invoked, you can't count on any of the references in your object as still being valid. They may have already been collected. You can release unmanaged resources (which is important), but that's about it.
You're right. Finalize is invoked non-deterministically, but Dispose must be called explicitly. My fault. :-O
If you truly believe you need to pick a mobile phone that "says something" about your personality, don't bother. You don't have a personality. A mental illness, maybe - but not a personality. - Charlie Brooker My Blog - My Photos - ScrewTurn Wiki
-
El Corazon wrote:
Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved.
That idiom is called "two-phase construction" and was widely used before exceptions were available for C++. For instance, MFC uses it all the time simply because VC++ didn't support exceptions at the time that MFC was designed. In general, today most experts including Stroustrup recommend avoiding two-phase construction, but some people don't use exceptions for one reason or another and they really have little choice: constructors can't return values to tell us if something went wrong :)
Nemanja Trifunovic wrote:
constructors can't return values to tell us if something went wrong
I've recently started using a library that makes all constructors inaccessible, and all objects must be created by a overloads of a static
Create
method on the object. eg:class MyClass { private MyClass() {} public static MyClass Create() { return new MyClass(); } }
I first thought that this was because constructors could not return failure codes, but as I type this, I realize that a static
Create
method with a specific return type can't return a status code either! Then I thought it was for serializing the object or something of that nature, but with reflection (in .NET), you can call a constructor as easily as any other method. My final thoughts on this, are that the Create method does not have to return a specific instance, while a constructor does. This means that in a complex hierarchy, you can be given a descendent object instead of the object you asked actually asked for, depending on how theCreate
method works. A highly contrived example:class ClassA { private ClassA() {} public static ClassA Create( int x ) { if ( x < 0 ) return new ClassA(); else return ClassB.Create(); } } class ClassB : ClassA { private ClassB() {} public static ClassB() { return new ClassB(); } } static void main() { ClassA myClass = ClassA.Create( 3 ); // Will really create a ClassB }
Is this what it's used for? Or am I heading into La-La Land with this line of thinking?
Sunrise Wallpaper Project | The StartPage Randomizer | A Random Web Page
-
Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
I think it depends. Normally I would lean towards the constructor based initialization but not always. In the end you have to decide whether it improves code readability. Here is an horror story which ought to go to the Coding Horrors. In my previous company, I was fixing an issue and in that file I found the following code:
void PostInvoice()
{
ApbhTivhStatusChange * pChg = new ApbhTivhStatusChange(m_pContext);
delete pChg;//Some other code follows this is where the real bug I was
//supposed to fix was
}After fixing the issue, I removed the first 3 lines of the function thinking that it was not doing anything as the process function was commented out. My bug fix worked correctly and I checked it in. I modified like this:
void PostInvoice()
{
//Some other code follows this is where the real bug I was
//supposed to fix was
}Later on is QA testing it was discovered that seem other piece of application functionality broke. It was embarrassing to find that the code I removed caused the issue. It was not a big issue to discover that the work was being done in the constructor and destructor of ApbhTivhStatusChange class.
class ApbhTivhStatusChange
{
private:
Context* m_pContext;public:
ApbhTivhStatusChange(Context* pContext)
{
pContext->ConnectToDatabase();
pContext->BalanceInvoice();
}~ApbhTivhStatusChange()
{
pContext->Cleanup();
}
}The above code was poorly written even though it worked. It caused a huge confusion. But one thing is for sure, you should always add clean up code in the destructor. There are very few cases where I found that it is not advisable to do so and of course you need to make sure that the destructors do not throw any exceptions but at the same time they log the exceptions.
Co-Author ASP.NET AJAX in Action
-
Patrick Sears wrote:
call them inside the constructor
There are very valid reasons to use them outside of the constructor as well. When one is developing the class, one needs to be clear as to the reasons why the constructor and destructors are separate.
Phil
pbraun wrote:
There are very valid reasons to use them outside of the constructor as well
I think the term 'as well' qualifies it really. IMHO it's fine to call the init() outside of the constructor as well, but seems foolish to not to call it at construct time - even if all it does is initialise the object to a NULL state.
-
Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
El Corazon wrote:
Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content
I find that argument totally bogus, the new operator creates an object instance, and then runs the constructor "over" that instance, the contructor is nothing more than a function which is automatically run when a new object instance is created, a constrructors raison d'etre is to initialise the object instance ready for use. By that score the constructor is badly named, it should have been called the initialiser :^)
- "I'm not lying, I'm just writing fiction with my mouth"
-
Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
If you want to bring it up with the team again, and I would personally, the name of the pattern that you use is called Resource Acquisition Is Initialization. The best reason for using this pattern, in my opinion, is that it is exception safe. If an exception happens it the object will be cleaned up automatically when the destructor is called, without you having to specifically needing to call the cleanup method. A quick google search for RAII will bring up plenty of reasons to discuss with your team should you ever find yourself in that argument again.
-
Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
Just to add on to what others have said, even with exceptions, in C++, an exception raised inside a constructor still poses a problem. For example, if you are using a pointer, and the constructor thew an exception, do you delete the object through that pointer? Is it needed/safe? It was safer to do just simple initialisations within the constructor, and put anything that can go wrong in a separate method.
-
Just to add on to what others have said, even with exceptions, in C++, an exception raised inside a constructor still poses a problem. For example, if you are using a pointer, and the constructor thew an exception, do you delete the object through that pointer? Is it needed/safe? It was safer to do just simple initialisations within the constructor, and put anything that can go wrong in a separate method.
Bijesh wrote:
For example, if you are using a pointer, and the constructor thew an exception, do you delete the object through that pointer?
The object automatically gets deleted if the construtcor throws an exception and the VC++ compiler implements this feature correctly. That's is the reason why if you create a placement form of new operator you also need to create a matching placement form of delete operator.
Co-Author ASP.NET AJAX in Action
-
Just to add on to what others have said, even with exceptions, in C++, an exception raised inside a constructor still poses a problem. For example, if you are using a pointer, and the constructor thew an exception, do you delete the object through that pointer? Is it needed/safe? It was safer to do just simple initialisations within the constructor, and put anything that can go wrong in a separate method.
-
If you want to bring it up with the team again, and I would personally, the name of the pattern that you use is called Resource Acquisition Is Initialization. The best reason for using this pattern, in my opinion, is that it is exception safe. If an exception happens it the object will be cleaned up automatically when the destructor is called, without you having to specifically needing to call the cleanup method. A quick google search for RAII will bring up plenty of reasons to discuss with your team should you ever find yourself in that argument again.
Janzen wrote:
the name of the pattern that you use is called Resource Acquisition Is Initialization.
Amen. Although it is surprising how many people refuse to grasp it.
-
I think it depends. Normally I would lean towards the constructor based initialization but not always. In the end you have to decide whether it improves code readability. Here is an horror story which ought to go to the Coding Horrors. In my previous company, I was fixing an issue and in that file I found the following code:
void PostInvoice()
{
ApbhTivhStatusChange * pChg = new ApbhTivhStatusChange(m_pContext);
delete pChg;//Some other code follows this is where the real bug I was
//supposed to fix was
}After fixing the issue, I removed the first 3 lines of the function thinking that it was not doing anything as the process function was commented out. My bug fix worked correctly and I checked it in. I modified like this:
void PostInvoice()
{
//Some other code follows this is where the real bug I was
//supposed to fix was
}Later on is QA testing it was discovered that seem other piece of application functionality broke. It was embarrassing to find that the code I removed caused the issue. It was not a big issue to discover that the work was being done in the constructor and destructor of ApbhTivhStatusChange class.
class ApbhTivhStatusChange
{
private:
Context* m_pContext;public:
ApbhTivhStatusChange(Context* pContext)
{
pContext->ConnectToDatabase();
pContext->BalanceInvoice();
}~ApbhTivhStatusChange()
{
pContext->Cleanup();
}
}The above code was poorly written even though it worked. It caused a huge confusion. But one thing is for sure, you should always add clean up code in the destructor. There are very few cases where I found that it is not advisable to do so and of course you need to make sure that the destructors do not throw any exceptions but at the same time they log the exceptions.
Co-Author ASP.NET AJAX in Action
Whoever wrote the original PostInvoice() and did not comment the purpose of the first two lines should be taken out and shot. BDF
-
Whoever wrote the original PostInvoice() and did not comment the purpose of the first two lines should be taken out and shot. BDF
The code actually evolved passing through several developers, the original developer might have done it correctly. It was probably the idea of a later developer who was a newbie to use the constructor an destructor to do all the work.
Co-Author ASP.NET AJAX in Action
-
The code actually evolved passing through several developers, the original developer might have done it correctly. It was probably the idea of a later developer who was a newbie to use the constructor an destructor to do all the work.
Co-Author ASP.NET AJAX in Action
Rama Krishna Vavilala wrote:
The code actually evolved passing through several developers, the original developer might have done it correctly. It was probably the idea of a later developer who was a newbie to use the constructor an destructor to do all the work.
we had something like that happen to us. It was in an Ascii to Latitude/Longitude routine. I forget the name of the method, but it supported several types of latitude or longitude references (dd.decimal or dd mm.dec or dd mm ss.dec). Another programmer got ahold of the method and continued addition additional inputs beyond even latitude and longitude, attempting the equivalent generalality of a scanf() for geodetic values. Pass about 6 months and no one knew these changes occured and everything was still going fine, until we tried to run a specific data set in a specific format, and intermittent jumps were occuring in the data. Turns out the new changes were not thread-safe, and the routine had grown so complex supporting so many types that it was a pain to track down! mind you, the method was still directly referenced as something to the extent of ascii 2 latlong in the name, so everyone thought it still did just that.
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
-
Nemanja Trifunovic wrote:
constructors can't return values to tell us if something went wrong
I've recently started using a library that makes all constructors inaccessible, and all objects must be created by a overloads of a static
Create
method on the object. eg:class MyClass { private MyClass() {} public static MyClass Create() { return new MyClass(); } }
I first thought that this was because constructors could not return failure codes, but as I type this, I realize that a static
Create
method with a specific return type can't return a status code either! Then I thought it was for serializing the object or something of that nature, but with reflection (in .NET), you can call a constructor as easily as any other method. My final thoughts on this, are that the Create method does not have to return a specific instance, while a constructor does. This means that in a complex hierarchy, you can be given a descendent object instead of the object you asked actually asked for, depending on how theCreate
method works. A highly contrived example:class ClassA { private ClassA() {} public static ClassA Create( int x ) { if ( x < 0 ) return new ClassA(); else return ClassB.Create(); } } class ClassB : ClassA { private ClassB() {} public static ClassB() { return new ClassB(); } } static void main() { ClassA myClass = ClassA.Create( 3 ); // Will really create a ClassB }
Is this what it's used for? Or am I heading into La-La Land with this line of thinking?
Sunrise Wallpaper Project | The StartPage Randomizer | A Random Web Page
http://en.wikipedia.org/wiki/Factory_method_pattern[^]
[My Blog]
"Visual studio desperately needs some performance improvements. It is sometimes almost as slow as eclipse." - Rüdiger Klaehn
"Real men use mspaint for writing code and notepad for designing graphics." - Anna-Jayne Metcalfe -
Just to add on to what others have said, even with exceptions, in C++, an exception raised inside a constructor still poses a problem. For example, if you are using a pointer, and the constructor thew an exception, do you delete the object through that pointer? Is it needed/safe? It was safer to do just simple initialisations within the constructor, and put anything that can go wrong in a separate method.
Bijesh wrote:
For example, if you are using a pointer, and the constructor thew an exception, do you delete the object through that pointer?
If the object was allocated using the non-placement (i.e. normal) version of
new
, the object is supposed to be "undone". However (last checked on VC++ 6.0), members of that object will only be cleaned up if they themselves were fully constructed at the time of the exception, so the object is destructed (as best it could be),new
returnsNULL
, so there is nothing to calldelete
on. If the object was allocated on the stack, that stack context will be destroyed by the stack unwinding that takes place, so again there is nothing to manually destroy/cleanup. Things change when you are dealing with placementnew
because you are basically directly calling the constructor to construct an object in a pre-allocated block of memory. What you do in that case depends on what you are using the block of memory for. You may free the entire block, or simply log the exception and continue with the next object reusing that block of memory. You just have to watch out for that exception so that you do not end up using that "partially constructed" object (which I have done before :doh: - that is why I know it is possible, and know that thevtbl
is/was the last thing to get initialized during construction). Not many developers need to implement their own fixed-size-block-allocator-based object cache, or otherwise deal with placementnew
, so issues with throwing exceptions from constructors is a non-issue for many. Peace!-=- James
Please rate this message - let me know if I helped or not! * * *
If you think it costs a lot to do it right, just wait until you find out how much it costs to do it wrong!
Avoid driving a vehicle taller than you and remember that Professional Driver on Closed Course does not mean your Dumb Ass on a Public Road!
See DeleteFXPFiles -
Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
One of the shortcomings of constructors (at least in the languages I've used) is that they aren't
virtual
. In this example, the Child class must define a constructor, but it simply calls the base constructor without adding any unique behaviour. If the constructor were inherited by the Child this wouldn't be necessary.public class Base
{
public string Name ;
public Base ( string Name )
{
this.Name = Name ;
}
}public class Child : Base
{
public Child ( string Name ) : base ( Name ) {}
}By defining a virtual Initialize method to do what the constructor would do (and allowing the compiler to provide an empty parameterless constructor), you get the desired behaviour.
public class Base
{
public string Name ;
public virtual Base Initialize ( string Name )
{
this.Name = Name ;
return ( this ) ;
}
}public class Child : Base {}
As you can see, the Child class needn't define a constructor, the empty parameterless constructor the compiler adds is enough and then the Child inherits the Initialize method, which it may override if and only if it needs to. (Note that Initialize returns a reference to the calling instance.) On the downside, using a class like this is a litte more complex, basically:
Child c = new Child() ;
c.Initialize ( "Zaphod" ) ;or
Child c = (Child) (new Child()).Initialize ( "Zaphod" ) ;
As you can see, saving time and effort writing and maintaining the classes costs some time and effort using the classes, so you have to decide for yourself which you prefer. I'd much rather have virtual constructors.
-
Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
Reading the above comments it seems that most people agree on a RAII model anyway. Requiring a sequence of steps to use simply sucks. RULE: the external interface should provide no surprises, and reduce complexity as much as possible. Both are usually violated by a "required sequence" class. So constructor-initialization and destructor-cleanup are my first choice, too, but there's a small footnote I'd add. In C++, creating a dynamic object is - compared to a "normal" data member - considered expensive and painful (unless you use smart pointers, which usually make it bearable). Also, there are some aggregation initialization scenarios where a direct initialization isn't feasible, e.g.:
class Gamma { public: void Gamma(Container * container) { m_container * container; } }; class Container { Gamma m_gamma; public: Container() : m_gamma(this) {} **//BAD IDEA!** }
You can now either make gamma dynamic:class Container { scoped_ptr m_gamma; public: Container() { m_gamma.reset(new Gamma(this)); } }
or you need to use an Init-Method. Still, in this case, there's a fixed patthern (rather two of them) I strictly follow:class Gamma
{
public:
Gamma() {... } // valid "not open" initialization
bool IsOpen();
void/errcode Open(...); // fails if IsOpen()
void Close(); // fails if IsOpen
~Gamma() { if (IsOpen() Close(); }
};i.e. the class is initialized correctly, if a resource is acquire can be queried using IsOpen, and the destructor cleans up if you don't close. (so Close is just an "early release of the resource", rather than a mandatory cleanup) Further, the class state must remain well-formed if you try to access the ressource if it isn*t acquired. Also, you must be able to use open and close a single instance as often as you like. One shot classes and "you can't call foo ever again after you called bar" are - unless this is a requirement of the ressource - teh h3ll. (just for the curious: the second pattern is just more relaxed, for the lazy me:
class Gamma
{
public:
bool IsOpen();
void/errcode Open() { Close(); ... }
void Close() { if (IsOpen()) { ... } }
~Gamma() { Close(); }
}the idea here is to move the IsOpen() calls from the caller into the class, so caller has to type less
We are a big screwed up dysfunctional psychotic happy fami
-
Just curious. Had this disagreement with my team a while back and lost. I didn't want to bring it up then as it would be pointless. But I am curious on a design issue with classes. I was brought up (admittedly on books for C++, not college), that constructors not only construct, but initialize everything so that the class is "ready to be used" alternately the destructor removes everything and cleans up after itself. This way there is never an issue as far as timing when you use the contents of a class. Others have promoted an init()/configure() methodology and cleanup()/clear() so that constructors construct the class, not the content, init()/configure() sets up the content, cleanup()/clear() removes the content (which I have used for specific reusable storage type classes, but never as a hard rule of everything) and destructor pretty much does nothing unless memory allocation is involved. Of course this also means, if threads are involved there requires an additional start() after configure() to get the ball rolling which creats a set of "do this first directives" in the documentation. :~ I do freely admit no college training, not sure if this is a college thing or not. I am not a lover of absolutes, but I did always like my classes clean so that they start and stop by scope properly (everything handled by constructors and destructors), and now I find myself staring at my code as if it is growing green, black and white mold with the recent changes to it. X| Is this a college teaching method? Have I been putting too much effort into organizing my classes as independant entities?
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
I only use two-stage construction when initialization can fail for a multitude of reasons AND the code creating the object needs to know which on the many reasons caused the failure. Constructors can't return values, so all you know is that it failed to construct. I use two-stage quite often when the class wraps some kind of communication. The class is not fully up and running until the comms are active, and I need to know why comms aren't active as the class starts up. Judy