all groups > c# > july 2006 >
c# :
throwing exception from constructor
Is it appropriate to throw exception from a constructor? Thats the only way i could think of to denote the failure of constructor, wherein i am invoking couple of other classes to initialise the object. TIA Sek
Contructor supposed to handle simple tasks like initialization. If up to the stage you need to throw exception from contructor I think I would suggest you to review the code. chanmm [quoted text, click to view] "Sek" <sek360@gmail.com> wrote in message news:1154412540.934030.81960@s13g2000cwa.googlegroups.com... > Is it appropriate to throw exception from a constructor? > > Thats the only way i could think of to denote the failure of > constructor, wherein i am invoking couple of other classes to > initialise the object. > > TIA > Sek >
As far as i know, It's not a appropriate way to throw exception from a constructor. If you can make sure that when exception occured, you should dispose all resoures, such as, File handler, memory, etc. Sek =E5=86=99=E9=81=93=EF=BC=9A [quoted text, click to view] > Is it appropriate to throw exception from a constructor? > > Thats the only way i could think of to denote the failure of > constructor, wherein i am invoking couple of other classes to > initialise the object. >=20 > TIA > Sek
[quoted text, click to view] Sek wrote: > Is it appropriate to throw exception from a constructor? > > Thats the only way i could think of to denote the failure of > constructor, wherein i am invoking couple of other classes to > initialise the object.
Yup, that's fine. Several framework types do it. For examples, see Guid(string), the FileStream constructors, and String(char[], int, int). Jon
[quoted text, click to view] simida wrote: > As far as i know, It's not a appropriate way to throw exception from a > constructor.
It's widely done, and there's no reason not to do it in .NET. In unmanaged C++ there are reasons why it's a bad idea, but they don't apply to .NET. [quoted text, click to view] > If you can make sure that when exception occured, you should dispose > all resoures, such as, File handler, memory, etc.
File handles etc, yes - but memory will automatically be cleaned up by the garbage collector. Jon
[quoted text, click to view] chanmm wrote: > Contructor supposed to handle simple tasks like initialization. If up to the > stage you need to throw exception from contructor I think I would suggest > you to review the code.
Initialization can quite often suggest throwing exceptions, particularly based on the parameters. What would you suggest FileStream should do if it's been asked to open a file for reading and the file doesn't exist? Jon
As many have stated it is ok to throw an exception in the constructor. Having said that i would recommend against it. Over the years i have found it helped me a lot better to just have constructors put the object into a safe state. I do work that might throw exceptions in a different method like Setup. I forget all the pains i had in the past that eventually brought my to doing things this way because I just do it as a matter of course now. Leon Lambert [quoted text, click to view] Sek wrote: > Is it appropriate to throw exception from a constructor? > > Thats the only way i could think of to denote the failure of > constructor, wherein i am invoking couple of other classes to > initialise the object. > > TIA > Sek
I agree with what Lambert wrote. I have always tried to insure that constructors simply put things into an "initialized" state. If you have to do something more involved, and especially anything that might throw an exception or have other failures, I always put them into a "Create" or "Open" type of function. Yes, this can lead to other errors (i.e. forgetting to call the appropriate Create function), but I just like it better because of all the "magic" constructors that happen behind your back (copy constructors, etc.). [quoted text, click to view] "Leon Lambert" wrote: > As many have stated it is ok to throw an exception in the constructor. > Having said that i would recommend against it. Over the years i have > found it helped me a lot better to just have constructors put the object > into a safe state. I do work that might throw exceptions in a different > method like Setup. I forget all the pains i had in the past that > eventually brought my to doing things this way because I just do it as a > matter of course now. > > Leon Lambert > > Sek wrote: > > Is it appropriate to throw exception from a constructor? > > > > Thats the only way i could think of to denote the failure of > > constructor, wherein i am invoking couple of other classes to > > initialise the object. > > > > TIA > > Sek > >
[quoted text, click to view] Leon Lambert wrote: > As many have stated it is ok to throw an exception in the constructor. > Having said that i would recommend against it. Over the years i have > found it helped me a lot better to just have constructors put the object > into a safe state. I do work that might throw exceptions in a different > method like Setup. I forget all the pains i had in the past that > eventually brought my to doing things this way because I just do it as a > matter of course now.
So how would you implement FileStream? If you don't do anything in the constructor, it's just saving the exception for later on - where's the advantage of that? Yes, the object would be in a "safe" state - but it's useless until it's opened the file, and that's the point at which you should throw an exception if the file can't be found, IMO. Jon
[quoted text, click to view] Brian C. Barnes wrote: > I agree with what Lambert wrote. I have always tried to insure that > constructors simply put things into an "initialized" state. If you have to do > something more involved, and especially anything that might throw an > exception or have other failures, I always put them into a "Create" or "Open" > type of function. Yes, this can lead to other errors (i.e. forgetting to call > the appropriate Create function), but I just like it better because of all > the "magic" constructors that happen behind your back (copy constructors, > etc.).
C# doesn't *have* "magic" constructors though. I really don't see the advantage of forcing the client to make two calls when one would do. The *only* point I could see is that if you're implementing IDisposable, you need to make sure that your constructor cleans up after itself if it throws an exception after acquiring a resource. If you do that in the Create method, you can assume that the client will call Dispose appropriately. However, using a Create/Initialize/etc method means that your object isn't really *usable* when the constructor has returned, which is the state I like to be in. It's quite possible that throwing exceptions from constructors is a bad idea in other environments, but I think it's fine in C#. Jon
[quoted text, click to view] Jon Skeet [C# MVP] wrote: > simida wrote: >> As far as i know, It's not a appropriate way to throw exception from >> a constructor. > > It's widely done, and there's no reason not to do it in .NET. In > unmanaged C++ there are reasons why it's a bad idea, but they don't > apply to .NET.
Excuse me? Indicating failure from a constructor is one of the primarly reason that exceptions were added to the C++ language over a decade ago. It is the proper way to signal failure from a constructor. Used together with the RAII idiom (resource acquisition is initialization - as manifested in smart pointers and tools like ScopeGuard), exceptions thrown from within a constructor are safe and easy to use correctly. The alternative, multi-part construction (via an "init" function), is an error-prone model than permits partially constructed objects to exist - something that the .NET designers felt so strongly about that they ensured that all objects are fully constructed before the first statement of the constructor runs. -cd
[quoted text, click to view] Barry Kelly wrote: > For similar reasons, in C# there's nothing wrong with throwing in the > constructor, and nor are there any complications or difficulties in > the mode of C++.
I'd really like to hear those "difficulties". It's quite normal to throw exceptions from C++ constructors - it's the one of the main reasons that exceptions were added to C++. -cd
[quoted text, click to view] Carl Daniel [VC++ MVP] wrote: > > It's widely done, and there's no reason not to do it in .NET. In > > unmanaged C++ there are reasons why it's a bad idea, but they don't > > apply to .NET. > > Excuse me? Indicating failure from a constructor is one of the primarly > reason that exceptions were added to the C++ language over a decade ago. It > is the proper way to signal failure from a constructor.
I think I must have heard exaggerated claims of the problems involved. I believe (after a quick search) that after an exception is thrown in a C++ constructor that the destructor is not called, so resources need to be cleaned up in that situation. I guess some people have taken that as a reason not to throw exceptions at all in C++... Jon
Sek, There are some good comments here already. The Framework Design Guidelines book says that it is acceptable to throw exceptions when appropriate. But, it also recommends keeping constructor operations simple. Often the only thing a constructor needs to do is capture the parameters. As a result many constructors should only need to throw on invalid parameters. I *usually* avoid long running or complex operations in constructors anyway because it's not clear to the caller that they're happening. If it makes more sense to construct an object in conjunction with a complex operation then I'll use a static factory method where I have the liberty of giving it a clear name using appropriate verbage. If you go with this approach (and I'm not suggesting that you do) then you'd naturally be limiting the circumstances where exceptions are thrown by constructors. Brian [quoted text, click to view] Sek wrote: > Is it appropriate to throw exception from a constructor? > > Thats the only way i could think of to denote the failure of > constructor, wherein i am invoking couple of other classes to > initialise the object. > > TIA > Sek
But the whole point of .NET is that it is language egnostic - and the libraries we write in C# may get used by C++/CLI projects, or other languages that perhaps can't deal with exceptions in constructors as cleanly as C# can. Since the author really doesn't know what language environment is being used, I would tend to stick with the more pessimistic approach of doing as little as possible in the constructor. [quoted text, click to view] > C# doesn't *have* "magic" constructors though. I really don't see the > advantage of forcing the client to make two calls when one would do. > The *only* point I could see is that if you're implementing > IDisposable, you need to make sure that your constructor cleans up > after itself if it throws an exception after acquiring a resource. If > you do that in the Create method, you can assume that the client will > call Dispose appropriately. >
[quoted text, click to view] Jon wrote: > My approach is to do what's appropriate in the constructor to create a > viable object. In the case of something like FileStream, that involves > opening the file - which would naturally involve throwing an exception > if the file cannot be opened. >
The FileStream constructor is another example of a poor design choice. IMHO, opening a file is not a simple operation. There should be an Open method (either instance or static) that performs this work. Even after reading the documentation it's still not perfectly clear that the constructor actually opens the file. But the deed has been done and throwing exceptions is the only appropriate choice. Brian
[quoted text, click to view] Barry Kelly wrote: > > The FileStream constructor is another example of a poor design choice. > > I strongly disagree! >
Well, it's definitely debatable. I can't honestly say that I even completely agree with my own statement nor do I always follow the "simple operation" rule for constructors myself. I just think there is a better alternative in this case. [quoted text, click to view] > > IMHO, opening a file is not a simple operation. There should be an > > Open method (either instance or static) that performs this work. > > This would create a three-state stream - closed, open and disposed - > rather than what we currently have, two states - open and disposed. With > an 'Open' operation, one would expect to be able to close and open it > repeatedly. I, for one, prefer objects with simple purposes in life and > with a minimum of 'modality'. >
And you'd get just that with a static factory method; a method with a verb name clearly describing what it is going to do.
Sek.. You can throw an exception in the constructor.. or use a static class factory and return null on failure.. or set a flag isValid to false. Beware that the finalizer will be called in C# even on exceptional construction! http://www.geocities.com/Jeff_Louie/oop30.htm C++ and PHP coders will be surprised to learn that in C# even if an exception is thrown in the user defined constructor, the user defined destructor will still be called. Regards, Jeff [quoted text, click to view] >>Is it appropriate to throw exception from a constructor?
Thats the only way i could think of to denote the failure of constructor, wherein i am invoking couple of other classes to initialise the object.<<
[quoted text, click to view] "chanmm" <chanmmn@hotmail.com> wrote: > Contructor supposed to handle simple tasks like initialization. If up to the > stage you need to throw exception from contructor
Interesting; the need to flag errors from constructors was one of the motivations for introducing exceptions into C++, since return value can't be used. There's nothing wrong with throwing an exception from a constructor. -- Barry --
[quoted text, click to view] "simida" <youchangping@gmail.com> wrote: > As far as i know, It's not a appropriate way to throw exception from a > constructor.
A constructor should leave an object in a valid state. If the constructor arguments do not give the right information to leave the object in a valid state with all its invariants holding, then the constructor should definitely throw an exception. -- Barry --
[quoted text, click to view] Leon Lambert <lambertl@inil.com> wrote: > As many have stated it is ok to throw an exception in the constructor. > Having said that i would recommend against it. Over the years i have > found it helped me a lot better to just have constructors put the object > into a safe state. I do work that might throw exceptions in a different > method like Setup. I forget all the pains i had in the past that > eventually brought my to doing things this way because I just do it as a > matter of course now.
I remember it being difficult to throw exceptions correctly in C++ constructors, but C# is not C++, and does not have many of its flaws. There was never a problem in throwing exceptions in constructors Delphi either, for a simple reason - Delphi initialized the object's fields to all-zeros before running the constructor. In Delphi, when a constructor threw an exception, the destructor was invoked. Because all the fields were initialized to zero, it was trivial for the destructor to correctly and safely destroy the partially-constructed object. The same is a lot harder in C++ when one is doing heap allocation etc. in the constructor. For similar reasons, in C# there's nothing wrong with throwing in the constructor, and nor are there any complications or difficulties in the mode of C++. -- Barry --
[quoted text, click to view] Brian C. Barnes <bcbarnes@newsgroups.nospam> wrote: > I agree with what Lambert wrote. I have always tried to insure that > constructors simply put things into an "initialized" state. If you have to do > something more involved, and especially anything that might throw an > exception or have other failures, I always put them into a "Create" or "Open" > type of function. Yes, this can lead to other errors (i.e. forgetting to call > the appropriate Create function), but I just like it better because of all > the "magic" constructors that happen behind your back (copy constructors, > etc.).
What magic constructors in C#? I suspect you're projecting C++'s language flaws on other object-oriented languages :) -- Barry --
[quoted text, click to view] Barry Kelly wrote: > One already has 'File.Open' and related methods which provide the > appropriate arguments to the FileStream constructor. > > But on the other hand - what's the benefit from using this approach?
File.Open doesn't have an ambiguous meaning. It's perfectly clear from the name that a file will be opened if no exceptions are thrown. The problem is that it's on a separate class, which is fine, but how would one know to look at the File class if they're currently interested in the FileStream class. It makes more sense to add it to the FileStream class as well. Consider the following lines of code. FileStream stream = new FileStream("foo.txt"); FileStream stream = FileStream.Open("foo.txt"); Without knowing anything about a FileStream what can we say about these lines of code? The only thing we can say for certain about the first line is that stream can be used to read/write data in the foo.txt file. We can say more about the second. Not only can it read/write to foo.txt, but it is *ready* to do so since the method clearly indicates that the stream is open when it's returned. But, that's not why I think it was a poor design choice. I think it's a poor design choice because a constructor that throws an IOException has a complex operation embedded in it. That contradicts the following guideline. "Do minimal work in the constructor. Constructors should not do much work other than to capture the constructor parameters. The cost of any other processing should be delayed until required." --Framework Design Guidelines by Cwalina & Abrams. [quoted text, click to view] > If > one calls the static method rather than using the constructor, what's > been gained over the losses: extra complexity, the divorce between where > the object is constructed (the static method) and the actual object > implementation, and the extra mode on the file stream?
I don't see where there's extra complexity. In fact, from the callers perspective the interface would be more self describing and thus simpler to use! You wouldn't necessarily have to move logic around to accomodate the factory method. Just make the constructor private and have the factory call that if you like. Using the static factory method approach it would still be impossible to reopen a closed stream since there wouldn't be an instance method there to do it. [quoted text, click to view] > Also, won't all > streams now need this Open() method?
Yep. That's how most of the objects that acquire resources in the System.Net and System.Data namespaces work. Though, in those examples they're usually instance methods. [quoted text, click to view] > What do you do when you get a > stream from elsewhere, like a NetworkStream from a socket? Do you need > to open that too? If not, where does all this documentation go?
I'd say no especially if the documentation on the stream indicated that a caller can assume it's open if the Close method hasn't been previously called. That's pretty much how it works now. The same semantics can be acheived with a static factory method.
[quoted text, click to view] Brian C. Barnes <bcbarnes@newsgroups.nospam> wrote: > But the whole point of .NET is that it is language egnostic - and the > libraries we write in C# may get used by C++/CLI projects, or other languages > that perhaps can't deal with exceptions in constructors as cleanly as C# can.
Care to cite any examples? Any language which can't cope with constructors throwing exceptions is in serious trouble when it comes to using the framework classes. [quoted text, click to view] > Since the author really doesn't know what language environment is being used, > I would tend to stick with the more pessimistic approach of doing as little > as possible in the constructor.
My approach is to do what's appropriate in the constructor to create a viable object. In the case of something like FileStream, that involves opening the file - which would naturally involve throwing an exception if the file cannot be opened. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
"Carl Daniel [VC++ MVP]" [quoted text, click to view] <cpdaniel_remove_this_and_nospam@mvps.org.nospam> wrote: > Barry Kelly wrote: > > For similar reasons, in C# there's nothing wrong with throwing in the > > constructor, and nor are there any complications or difficulties in > > the mode of C++. > > I'd really like to hear those "difficulties". It's quite normal to throw > exceptions from C++ constructors - it's the one of the main reasons that > exceptions were added to C++.
I know - I mentioned it in a parallel post. Consider (implementions inlined, copy constructors / assignment operators / auto_ptr etc. all ignored, for the sake of exposition): ---8<--- class Foo { private: Bar *m_bar; public: Foo(bool doThrow) { m_bar = new Bar; if (doThrow) throw 0; } ~Foo() { delete m_bar; } }; --->8--- The same in Delphi: ---8<--- type Foo = class private FBar: Bar; public constructor Create(doThrow: Boolean); // inlined here for exposition, not actually valid Delphi syntax begin FBar = Bar.Create; if doThrow then throw Exception.Create; end; destructor Destroy; override; begin FBar.Free; // Free() checks for nil pointer first end; end; --->8--- -- Barry --
[quoted text, click to view] Brian Gideon <briangideon@yahoo.com> wrote: > Jon wrote: > > My approach is to do what's appropriate in the constructor to create a > > viable object. In the case of something like FileStream, that involves > > opening the file - which would naturally involve throwing an exception > > if the file cannot be opened. > > The FileStream constructor is another example of a poor design choice. > IMHO, opening a file is not a simple operation. There should be an > Open method (either instance or static) that performs this work. Even > after reading the documentation it's still not perfectly clear that the > constructor actually opens the file. But the deed has been done and > throwing exceptions is the only appropriate choice.
Having a FileStream which hasn't opened the file seems pretty odd to me - and would mean that you'd have extra code in everything which used it. Having no public constructors, just static methods, would be doable - but I don't see the advantage. From the client's point of view there'd still be an exception occurring. Where's the benefit in making the constructor *not* open the file? I'm all for constructors only doing a sensible amount of work - but not when that means that an object isn't actually ready for use until another particular method has been called. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
[quoted text, click to view] "Brian Gideon" <briangideon@yahoo.com> wrote: > Jon wrote: > > My approach is to do what's appropriate in the constructor to create a > > viable object. In the case of something like FileStream, that involves > > opening the file - which would naturally involve throwing an exception > > if the file cannot be opened. > > The FileStream constructor is another example of a poor design choice.
I strongly disagree! [quoted text, click to view] > IMHO, opening a file is not a simple operation. There should be an > Open method (either instance or static) that performs this work.
This would create a three-state stream - closed, open and disposed - rather than what we currently have, two states - open and disposed. With an 'Open' operation, one would expect to be able to close and open it repeatedly. I, for one, prefer objects with simple purposes in life and with a minimum of 'modality'. -- Barry --
[quoted text, click to view] "Brian Gideon" <briangideon@yahoo.com> wrote: > Barry Kelly wrote: > > > The FileStream constructor is another example of a poor design choice. > > > > I strongly disagree! > > Well, it's definitely debatable. I can't honestly say that I even > completely agree with my own statement nor do I always follow the > "simple operation" rule for constructors myself. I just think there is > a better alternative in this case. > > > > IMHO, opening a file is not a simple operation. There should be an > > > Open method (either instance or static) that performs this work. > > > > This would create a three-state stream - closed, open and disposed - > > rather than what we currently have, two states - open and disposed. With > > an 'Open' operation, one would expect to be able to close and open it > > repeatedly. I, for one, prefer objects with simple purposes in life and > > with a minimum of 'modality'. > > And you'd get just that with a static factory method; a method with a > verb name clearly describing what it is going to do.
One already has 'File.Open' and related methods which provide the appropriate arguments to the FileStream constructor. But on the other hand - what's the benefit from using this approach? If one calls the static method rather than using the constructor, what's been gained over the losses: extra complexity, the divorce between where the object is constructed (the static method) and the actual object implementation, and the extra mode on the file stream? Also, won't all streams now need this Open() method? What do you do when you get a stream from elsewhere, like a NetworkStream from a socket? Do you need to open that too? If not, where does all this documentation go? -- Barry --
[quoted text, click to view] Jon Skeet [C# MVP] wrote: > Carl Daniel [VC++ MVP] wrote: >>> It's widely done, and there's no reason not to do it in .NET. In >>> unmanaged C++ there are reasons why it's a bad idea, but they don't >>> apply to .NET. >> >> Excuse me? Indicating failure from a constructor is one of the >> primarly reason that exceptions were added to the C++ language over >> a decade ago. It is the proper way to signal failure from a >> constructor. > > I think I must have heard exaggerated claims of the problems involved. > I believe (after a quick search) that after an exception is thrown in > a > C++ constructor that the destructor is not called, so resources need > to > be cleaned up in that situation. I guess some people have taken that > as > a reason not to throw exceptions at all in C++...
That's correct - the body of the destructor is not run, but the destructors of all base classes and member variables are run (assuming the exception was thrown from the body of the constructor). If you use the RAII pattern (as all modern C++ programmers should), your constructor and destructor bodies will almost always be empty and throwing an exception from the constructor will do exactly what you'd want it to do. -cd
[quoted text, click to view] Jeff Louie <jeff_louie@yahoo.com> wrote: > Sek.. You can throw an exception in the constructor.. or use a static > class factory > and return null on failure.. or set a flag isValid to false. > > Beware that the finalizer will be called in C# even on exceptional > construction! > > http://www.geocities.com/Jeff_Louie/oop30.htm > > C++ and PHP coders will be surprised to learn that in C# even if an > exception is > thrown in the user defined constructor, the user defined destructor will > still be > called. On the other hand, Delphi programmers won't be surprised - although calling C# '~Class()' syntax a 'destructor' is, of course, an abuse of terminology... :) -- Barry --
[quoted text, click to view] "Brian Gideon" <briangideon@yahoo.com> wrote: > Barry Kelly wrote: > > One already has 'File.Open' and related methods which provide the > > appropriate arguments to the FileStream constructor. > > > > But on the other hand - what's the benefit from using this approach? > > "Do minimal work in the constructor. Constructors should not do much > work other than to capture the constructor parameters. The cost of any > other processing should be delayed until required." --Framework Design > Guidelines by Cwalina & Abrams.
I agree with the general principle that constructors should not initiate an operation that is costly in time or space, but I don't agree with the notion that a constructor should delay 'full initialization with all invariants holding' until a later 'Initialize' method is called. All that does is complicate the interface, multiply the possible states, etc. etc. I'm more interested in how you think the rationale behind the guideline applies in this particular case. Or to put it another way, I think there's a balance to be achieved - described below. [quoted text, click to view] > > If > > one calls the static method rather than using the constructor, what's > > been gained over the losses: extra complexity, the divorce between where > > the object is constructed (the static method) and the actual object > > implementation, and the extra mode on the file stream? > > I don't see where there's extra complexity. In fact, from the callers > perspective the interface would be more self describing and thus > simpler to use!
I can only talk about my personal experience using different classes. I personally find FileStream nice and easy to work with, and I like its idiom. On the other hand, I find System.Diagnostics.Process far more awkward. I need to construct an instance, fiddle with various properties before finally invoking a method. Now, starting a process etc. is an expensive operation. As such, it shouldn't occur inside the constructor. What's more, the various subtleties and options on how one can create a process aren't fully appreciated by people who are new to the functionality. With respect to creating a process, I think the static method approach along with a do-very-little constructor and tweakable properties works well - though the static methods are missing in the current version of the BCL. Thus, I think it's a question of where one draws the line. I think that FileStream is good and that making it a tweakable stillborn object until you finally call 'Open()' would be overkill. Just MHO. I think it has more to do with the cost of the operation than the fact that it may or may not throw exceptions. [quoted text, click to view] > You wouldn't necessarily have to move logic around to accomodate the > factory method. Just make the constructor private and have the factory > call that if you like. > > Using the static factory method approach it would still be impossible > to reopen a closed stream since there wouldn't be an instance method > there to do it.
This is more an argument for named constructors, but I think that's an orthogonal topic to throwing exceptions from constructors. [quoted text, click to view] > > Also, won't all > > streams now need this Open() method? > > Yep. That's how most of the objects that acquire resources in the > System.Net and System.Data namespaces work. Though, in those examples > they're usually instance methods.
But these objects typically block for lengthy time periods. I would agree to a rule of thumb that says "any operation that you might consider making asynchronous doesn't belong in a constructor". -- Barry --
[quoted text, click to view] Barry Kelly wrote: <snip> > > Consider (implementions inlined, copy constructors / assignment > operators / auto_ptr etc. all ignored, for the sake of exposition): > > ---8<--- > class Foo > { > private: > Bar *m_bar; > > public: > Foo(bool doThrow) > { > m_bar = new Bar; > if (doThrow) > throw 0; > } > > ~Foo() > { > delete m_bar; > } > }; > --->8---
I think you're projecting your C# way of thinking onto C++, therefore doing unwise design choices... Why is the m_bar member allocated allocated on the heap? Any reason for that in the 1st place ???? 9 times out of 10, the good solution is as imple as : class Foo { Bar m_bar; //no need for constructor nor destructor }; Now, suppose there is a good reason to allocate m_bar on the heap, what about doing modern C++, eg usig the RAII idiom ?? class Foo { std::auto_ptr<Bar> m_bar; //depending on context, boost::shared_ptr may be another option public: Foo(bool doThrow) : m_bar(new Bar()) { if (doThrow) throw 0; } }; Arnaud MVP - VC
[quoted text, click to view] Barry Kelly <barry.j.kelly@gmail.com> wrote: > FBar = Bar.Create; > if doThrow then > throw Exception.Create;
I've been programming in too many different languages lately. That should be: FBar := Bar.Create; if doThrow then raise Exception.Create('blah'); -- Barry --
[quoted text, click to view] Jon wrote: > Brian Gideon <briangideon@yahoo.com> wrote: > Having a FileStream which hasn't opened the file seems pretty odd to me > - and would mean that you'd have extra code in everything which used > it. Having no public constructors, just static methods, would be doable > - but I don't see the advantage. From the client's point of view > there'd still be an exception occurring. > > Where's the benefit in making the constructor *not* open the file? I'm > all for constructors only doing a sensible amount of work - but not > when that means that an object isn't actually ready for use until > another particular method has been called. >
I realize I'm splitting hairs on this one, but the main advantage IMHO is better compliance with the guideline. Anything that throws an IOException can't possibly be a simple operation. If you use the static factory method approach then you would have an object that's ready to use in one call with the added benefit that the interface should be easier to understand for the caller. I think one advantage of the guideline is that it encourages developers to put complex operations in methods where 1) they're expected and 2) that have self describing names. To me anyway, line 2 is an order of magnitude more clear that the stream is open than line 1. FileStream stream = new FileStream("foo.txt"); // Line 1 FileStream stream = FileStream.Open("foo.txt"); // Line 2 I'm not saying that throwing exceptions from a constructor is bad. In fact the same guidelines say it's acceptable when appropriate. Since the FileStream does attempt to open a file then throwing an exception is a logical choice.
[quoted text, click to view] adebaene@club-internet.fr wrote: > Barry Kelly wrote: > <snip> > > > > Consider (implementions inlined, copy constructors / assignment > > operators / auto_ptr etc. all ignored, for the sake of exposition): > > > > ---8<--- > > class Foo > > { > > private: > > Bar *m_bar; > > > > public: > > Foo(bool doThrow) > > { > > m_bar = new Bar; > > if (doThrow) > > throw 0; > > } > > > > ~Foo() > > { > > delete m_bar; > > } > > }; > > --->8--- > > I think you're projecting your C# way of thinking onto C++, therefore > doing unwise design choices... > > Why is the m_bar member allocated allocated on the heap?
That's irrelevant. This isn't a program, so there are no design choices. There are only language features. [quoted text, click to view] > Now, suppose there is a good reason to allocate m_bar on the heap, what > about doing modern C++, eg usig the RAII idiom ??
I explicitly mentioned that I was ignoring auto_ptr for the sake of exposition. In my view, C++'s destructors along with the RAII pattern are basically required to be overused in order to hack around a limitation in the language. The RAII pattern works very well for simple scenarios (and they should be used in such reusable scenarios), like an owned pointer or a ref-counted pointer, but not every paired operation between constructor and destructor is so reusable that it merits a new type. -- Barry --
[quoted text, click to view] Brian Gideon <briangideon@yahoo.com> wrote: > > Where's the benefit in making the constructor *not* open the file? I'm > > all for constructors only doing a sensible amount of work - but not > > when that means that an object isn't actually ready for use until > > another particular method has been called. > > I realize I'm splitting hairs on this one, but the main advantage IMHO > is better compliance with the guideline. Anything that throws an > IOException can't possibly be a simple operation. If you use the > static factory method approach then you would have an object that's > ready to use in one call with the added benefit that the interface > should be easier to understand for the caller.
To split hairs even further, I regard compliance with guidelines per se as not being an advantage at all - it's only an advantage to the extent that the guideline itself makes sense. Clearly I disagree with the generality of the guideline in this case, so compliance with it is irrelevant to me. [quoted text, click to view] > I think one advantage of the guideline is that it encourages developers > to put complex operations in methods where 1) they're expected and 2) > that have self describing names. To me anyway, line 2 is an order of > magnitude more clear that the stream is open than line 1.
*That* is much more of an argument I can at least understand. I still disagree with it, largely because opening the stream on construction is precisely the behaviour I expect, but at least it's a reasonable argument :) -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
"Barry Kelly" <barry.j.kelly@gmail.com> a écrit dans le message de news: acf1d2pj19bjlppmfs4r3qbsmg5termkpg@4ax.com... [quoted text, click to view] > adebaene@club-internet.fr wrote: > In my view, C++'s destructors along with the RAII pattern are basically > required to be overused in order to hack around a limitation in the > language.
Which limitation? The limitation is rather on the .NET finalizer side IMHO : since you don't know when they are run, there is almost nothing you can do inside them! [quoted text, click to view] > The RAII pattern works very well for simple scenarios (and > they should be used in such reusable scenarios), like an owned pointer > or a ref-counted pointer, but not every paired operation between > constructor and destructor is so reusable that it merits a new type.
That's why there are generic solutions to the RAII idiom, such as ScopeGuard ( http://www.ddj.com/dept/cpp/184403758) Arnaud MVP - VC
"Barry Kelly" <barry.j.kelly@gmail.com> a écrit dans le message de news: gf55d25vi26gqbfm8p72mfskjjt6ihbjeg@4ax.com... [quoted text, click to view] > "Arnaud Debaene" <adebaene@club-internet.fr> wrote: > >> "Barry Kelly" <barry.j.kelly@gmail.com> a écrit dans le message de news: >> acf1d2pj19bjlppmfs4r3qbsmg5termkpg@4ax.com... >> > adebaene@club-internet.fr wrote: >> >> > In my view, C++'s destructors along with the RAII pattern are basically >> > required to be overused in order to hack around a limitation in the >> > language. >> Which limitation? The limitation is rather on the .NET finalizer side >> IMHO : >> since you don't know when they are run, there is almost nothing you can >> do >> inside them! > > We'll have to agree to disagree - I think it's a limitation of the > language definition, nothing to do with .NET or otherwise, in the > context of "throwing an exception from the constructor".
But which limitation are you talking about exactly? That's what I don't understand... [quoted text, click to view] >> > The RAII pattern works very well for simple scenarios (and >> > they should be used in such reusable scenarios), like an owned pointer >> > or a ref-counted pointer, but not every paired operation between >> > constructor and destructor is so reusable that it merits a new type. >> >> That's why there are generic solutions to the RAII idiom, such as >> ScopeGuard >> ( http://www.ddj.com/dept/cpp/184403758) > > Yes, more hacks and crutches... Huuh? Andrei Alexdandrescu doing "hacks and crutchs" ??? Care to justify your appreciation? More seriously, I believe there is a true divergence ni philosophy here : The C++ approach is "do as little as possible in language itself, and as much as possible in libraries", whereas your approach (I am not really sure this is indeed the C# approach) is "put everything in language and compiler itself, so that there is nothing left to do in libraries". I believe the 1st approach is more flexible because, first, it makes it much easier to replace a defective component.... Arnaud MVP - VC
[quoted text, click to view] "Arnaud Debaene" <adebaene@club-internet.fr> wrote: > "Barry Kelly" <barry.j.kelly@gmail.com> a écrit dans le message de news: > gf55d25vi26gqbfm8p72mfskjjt6ihbjeg@4ax.com... > > We'll have to agree to disagree - I think it's a limitation of the > > language definition, nothing to do with .NET or otherwise, in the > > context of "throwing an exception from the constructor". > > But which limitation are you talking about exactly? That's what I don't > understand...
Like I said, we'll have to agree to disagree. [quoted text, click to view] > More seriously, I believe there is a true divergence ni philosophy here : > The C++ approach is "do as little as possible in language itself, and as > much as possible in libraries",
Nonsense! If that were true, the language would look like LISP! :P [quoted text, click to view] > whereas your approach (I am not really sure > this is indeed the C# approach) is "put everything in language and compiler > itself, so that there is nothing left to do in libraries".
That's clearly not true, because there seem to be substantial libraries packaged with the .NET framework. :) Even the C# basic types are defined in a library! You'll have to forgive me, I'm being quite facetious, at the end of a long day. [quoted text, click to view] > I believe the 1st > approach is more flexible because, first, it makes it much easier to replace > a defective component....
Consider std::stack::pop() - C++ is a language in which you can't even write an exception-safe mutator method which returns a value of a user-defined type! I think a programming language should have a carefully selected set of abstractions and abstraction creation tools that are suitable for the domain to which it is applied. I think C++ has a set of useful abstractions and abstraction creation tools, but there are interactions between some of them that are less than desirable - and that the resulting sum is somewhat less than the sum of its parts. I think it would be a better language if it removed some features, and changed some functionality - but then it would no longer be C++. -- Barry --
[quoted text, click to view] "Arnaud Debaene" <adebaene@club-internet.fr> wrote: > "Barry Kelly" <barry.j.kelly@gmail.com> a écrit dans le message de news: > acf1d2pj19bjlppmfs4r3qbsmg5termkpg@4ax.com... > > adebaene@club-internet.fr wrote: > > > In my view, C++'s destructors along with the RAII pattern are basically > > required to be overused in order to hack around a limitation in the > > language. > Which limitation? The limitation is rather on the .NET finalizer side IMHO : > since you don't know when they are run, there is almost nothing you can do > inside them!
We'll have to agree to disagree - I think it's a limitation of the language definition, nothing to do with .NET or otherwise, in the context of "throwing an exception from the constructor". [quoted text, click to view] > > The RAII pattern works very well for simple scenarios (and > > they should be used in such reusable scenarios), like an owned pointer > > or a ref-counted pointer, but not every paired operation between > > constructor and destructor is so reusable that it merits a new type. > > That's why there are generic solutions to the RAII idiom, such as ScopeGuard > ( http://www.ddj.com/dept/cpp/184403758) Yes, more hacks and crutches... -- Barry --
[quoted text, click to view] Barry Kelly wrote: > > "Do minimal work in the constructor. Constructors should not do much > > work other than to capture the constructor parameters. The cost of any > > other processing should be delayed until required." --Framework Design > > Guidelines by Cwalina & Abrams. > > I agree with the general principle that constructors should not initiate > an operation that is costly in time or space, but I don't agree with the > notion that a constructor should delay 'full initialization with all > invariants holding' until a later 'Initialize' method is called. All > that does is complicate the interface, multiply the possible states, > etc. etc. I'm more interested in how you think the rationale behind the > guideline applies in this particular case. >
My rationale is based on the fact that some FileStream constructors acquire a resource in a complex manner. To me, opening a file, which may require network activity, does not qualify as "minimal work". [quoted text, click to view] > Or to put it another way, I think there's a balance to be achieved - > described below. >
There's always a balance. That's why I can't honestly say I'm too hung up about it. There are other interface design problems in the BCL that are more significant. And it's certainly possible that I'm interpreting the guideline too strictly. But, it did come from people who are smarter than I so I want to be cautious about ignoring it altogether. [quoted text, click to view] > I can only talk about my personal experience using different classes. I > personally find FileStream nice and easy to work with, and I like its > idiom. On the other hand, I find System.Diagnostics.Process far more > awkward. I need to construct an instance, fiddle with various properties > before finally invoking a method. > > Now, starting a process etc. is an expensive operation. As such, it > shouldn't occur inside the constructor. What's more, the various > subtleties and options on how one can create a process aren't fully > appreciated by people who are new to the functionality. With respect to > creating a process, I think the static method approach along with a > do-very-little constructor and tweakable properties works well - though > the static methods are missing in the current version of the BCL. > > Thus, I think it's a question of where one draws the line. I think that > FileStream is good and that making it a tweakable stillborn object until > you finally call 'Open()' would be overkill. Just MHO.
I don't know. Even if Open were an instance method I'm not sure it would seem overkill to me. Afterall, that's how a lot (most?) of the classes in the BCL work. But, you're right, as it is, the FileStream class works well. [quoted text, click to view] > I think it has more to do with the cost of the operation than the fact > that it may or may not throw exceptions.
Yeah, I mean the exceptions that a constructor throws should have little impact on how the guideline is followed. I just think opening a file is a potentially expensive and complex operation. [quoted text, click to view] > This is more an argument for named constructors, but I think that's an > orthogonal topic to throwing exceptions from constructors. >
You're right. We could probably start a whole thread on that topic. [quoted text, click to view] > But these objects typically block for lengthy time periods. I would > agree to a rule of thumb that says "any operation that you might > consider making asynchronous doesn't belong in a constructor". >
It's probably a bit too specific to include in any formal documentation. But, it does sound reasonable to me.
Don't see what you're looking for? Try a search.
|
|
|