I'm working on a C++ class library for thread synchronization purposes that encapsulates the OS's Mutexes, Threads etc. If, for any reason, the creation of a C++ sync-object fails because of the underlying system function call, this is such a severe condition that the object should not be usable at all.
Now I need to make the design decision on how to handle this condition. I've come up with two main options. I'll call the example class "Mutex":
a.) The constructor Mutex() throws an exception indicating that object creation failed.
b.) The object is created in an "invalid" state that can be queried by a method like "bool Mutex::isValid() const". Every other method invocation on the object, for example Mutex::lock(), throws an exception.
Personally, I prefer procedure b.), but I've noticed that all Java classes use a.) Is that a hint to the right design? Mutex objects will most likely be members of other classes, thus an exception thrown in the ctor will be thrown out of those enclosing ctors. Could that be a problem? What do the C++ experts think?
> I'm working on a C++ class library for thread synchronization purposes > that encapsulates the OS's Mutexes, Threads etc. > If, for any reason, the creation of a C++ sync-object fails because of > the underlying system function call, this is such a severe condition > that the object should not be usable at all.
> Now I need to make the design decision on how to handle this condition. > I've come up with two main options. I'll call the example class "Mutex":
> a.) The constructor Mutex() throws an exception indicating that object > creation failed.
> b.) The object is created in an "invalid" state that can be queried by a > method like "bool Mutex::isValid() const". > Every other method invocation on the object, for example Mutex::lock(), > throws an exception.
> Personally, I prefer procedure b.), but I've noticed that all Java > classes use a.) Is that a hint to the right design? > Mutex objects will most likely be members of other classes, thus an > exception thrown in the ctor will be thrown out of those enclosing > ctors. Could that be a problem? > What do the C++ experts think?
> Thanks in advance, > Gernot
Throwing an exception in a constructor is one of the better-designed features of C++. If you follow the rules, the right things happen. Use it when you can.
John Nagle Animats
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Gernot Neppert wrote: > a.) The constructor Mutex() throws an exception indicating that object > creation failed.
> b.) The object is created in an "invalid" state that can be queried by a > method like "bool Mutex::isValid() const". > Every other method invocation on the object, for example Mutex::lock(), > throws an exception.
> Personally, I prefer procedure b.), [...]
IMHO it's usually best to report an error as early as possible.
If the constructor throws an exception, there is no Mutex instance at all, so you need not check for validity in every member function of your Mutex class.
Additionally, if a user of the Mutex class is expected to call the isValid member function after construction of a Mutex instance, she has to write an error handler anyway.
Maybe the user omits the isValid() call and there has been some expensive calculation between the (failed) construction of the Mutex and the first usage of the Mutex. In some cases, a delayed error message could render all the calculation useless.
If the synchronisation is never used (perhaps the object is not actually used) then it would have been wrong to throw in the constructor. As a rule, code should not fail simply because it foresees trouble later, if for no other reason than that it might actually succeed later. (The system may be less busy.)
However, I think it's acceptable to throw from a constructor if the object exists only to provide an exception safe wrapping around some operation. The Lock class (below) is an example. Your Mutex::isValid() function is a bad idea, since it is tedious for the client. Instead, you want a private lazyConstruct() function (which throws).
The following classes are offered up for sacrifice. If you use the Lockable class as a protected base class, then members of the derived classes can write simply "Lock lk(this);" when they wish to gain exclusive access to their data. (If you inherit publically, then clients can lock the derived class object.)
The Lockable member functions might be better defined out of line, but the nested Lock class wants to be fully inline.
class Lockable { HANDLE osHandle; void lazyConstruct() { if (osHandle) return; osHandle = CreateMutex(NULL, FALSE, NULL); if (not osHandle) throw Exception; } protected: Lockable() // protected to force derivation { osHandle = NULL; } ~Lockable() { if (osHandle) CloseHandle(osHandle); } void Lock() { lazyConstruct(); WaitForSingleObject(osHandle, INFINITE); } void Unlock() { if (osHandle) ReleaseMutex(osHandle); }
| a.) The constructor Mutex() throws an exception indicating that object | creation failed.
This is a much cleaner solution, in my opinion.
| Mutex objects will most likely be members of other classes, thus an | exception thrown in the ctor will be thrown out of those enclosing | ctors. Could that be a problem?
No, it shouldn't be a problem, as long as you follow the principles of resource management (see http://www.relisoft.com/resource )
Bartosz
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
If the synchronisation is never used (perhaps the object is not actually used) then it would have been wrong to throw in the constructor. As a rule, code should not fail simply because it foresees trouble later, if for no other reason than that it might actually succeed later. (The system may be less busy.)
However, I think it's acceptable to throw from a constructor if the object exists only to provide an exception safe wrapping around some operation. The Lock class (below) is an example. Your Mutex::isValid() function is a bad idea, since it is tedious for the client. Instead, you want a private lazyConstruct() function (which throws).
The following classes are offered up for sacrifice. If you use the Lockable class as a protected base class, then members of the derived classes can write simply "Lock lk(this);" when they wish to gain exclusive access to their data. (If you inherit publically, then clients can lock the derived class object.)
The Lockable member functions might be better defined out of line, but the nested Lock class wants to be fully inline.
class Lockable { HANDLE osHandle; void lazyConstruct() { if (osHandle) return; osHandle = CreateMutex(NULL, FALSE, NULL); if (not osHandle) throw Exception; } protected: Lockable() // protected to force derivation { osHandle = NULL; } ~Lockable() { if (osHandle) CloseHandle(osHandle); } void Lock() { lazyConstruct(); WaitForSingleObject(osHandle, INFINITE); } void Unlock() { if (osHandle) ReleaseMutex(osHandle); }
> [...] > Now I need to make the design decision on how to handle this condition. > I've come up with two main options. I'll call the example class "Mutex":
> a.) The constructor Mutex() throws an exception indicating that object > creation failed.
> b.) The object is created in an "invalid" state that can be queried by a > method like "bool Mutex::isValid() const". > Every other method invocation on the object, for example Mutex::lock(), > throws an exception.
> Personally, I prefer procedure b.), but I've noticed that all Java > classes use a.) Is that a hint to the right design?
I don't want to offend you, but (b) is simply idiotic. If the creation of an object failed, throw an exception. Anything else will cause many lines of error checking code which is just braindamaged because exceptions have been introduced to remove error checking code from places where they shouldn't be. And what else do you want to do later, but throwing an exception ?!?
Use (a), thats correct, simple, elegant, efficient, readable, logical, anything.
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> Mutex objects will most likely be members of other classes, thus an > exception thrown in the ctor will be thrown out of those enclosing > ctors. Could that be a problem? > What do the C++ experts think?
The question to ask, is there anything that classes containing your mutex could normally do in the event of this failure? More than likely not. You would face the same thing for any class that allocates memory in the constructor. That allocation might fail and throw an exception. I doubt anyone represents such failure as state.
-- David Bradley bradleyd@>REMOVE THIS<digineer.com
Gernot Neppert <GernotNepp...@compuserve.com> wrote in message
> I've come up with two main options. I'll call the example class "Mutex":
> a.) The constructor Mutex() throws an exception indicating that object > creation failed.
> b.) The object is created in an "invalid" state that can be queried by a > method like "bool Mutex::isValid() const". > Every other method invocation on the object, for example Mutex::lock(), > throws an exception.
> Personally, I prefer procedure b.), but I've noticed that all Java > classes use a.) Is that a hint to the right design?
I prefer the first option. (Unless the compiler has bugs in dealing with exceptions thrown from constructors, of course.) Having a non-usable object doesn't serve any purpose. If you are going to put checks and exceptions in every member function, it will complicate the implementation of the class. The only thing you have to be careful about is that your constructors should be exception-safe.
> Mutex objects will most likely be members of other classes, thus an > exception thrown in the ctor will be thrown out of those enclosing > ctors. Could that be a problem?
It won't be a problem if the enclosing constructors are exception safe. The exceptions from contained object's constructor will be propagated outwards after the partially constructed part of the outer object is properly destructed.
Regards, Biju Thomas
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Gernot Neppert wrote in message <3874C62B.3BE1...@compuserve.com>... >Now I need to make the design decision on how to handle this condition. >I've come up with two main options. I'll call the example class "Mutex":
>a.) The constructor Mutex() throws an exception indicating that object >creation failed.
>b.) The object is created in an "invalid" state that can be queried by a >method like "bool Mutex::isValid() const". >Every other method invocation on the object, for example Mutex::lock(), >throws an exception.
>Personally, I prefer procedure b.), but I've noticed that all Java >classes use a.) Is that a hint to the right design? >Mutex objects will most likely be members of other classes, thus an >exception thrown in the ctor will be thrown out of those enclosing >ctors. Could that be a problem?
Throw an exception.
If you use the valid/invalid state technique then you have to add validity checks that the object was successfully created. Are you going to throw an exception from there? If so, why not throw the exception to begin with? If not, then you have to add more validity checks in other places which not only clutters the code, but is also error prone - did you remember to add the validity check everywhere? If not, your code may inexplicably crash or produce incorrect results.
Throwing or propagating an exception out of a constructor can cause problems if you don't follow the "resource acquisition is initialization" technique described by Stroustrup and others. See http://www.relisoft.com/resource/ for a description of how to implement this technique.
I'm curious why you prefer "b"? Is it because you aren't comfortable with exceptions?
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
My reason to avoid throwing from constructors is a potential resource leak problem. If you have
A::A { m_p = new char[1024]; throw 1;
}
A::~A() { delete [] m_p;
}
void main() { try{ A a; } catch(...) { }
}
, the destructor for 'a' will never be called, because the object hasn't been fully constructed. If you use objects every time you allocate something, like auto-pointers, then throwing from a constructor is OK.
* Sent from RemarQ http://www.remarq.com The Internet's Discussion Network * The fastest and easiest way to search and participate in Usenet - Free!
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
|> Gernot Neppert schrieb: |> > [...] |> > Now I need to make the design decision on how to handle this condition. |> > I've come up with two main options. I'll call the example class "Mutex":
|> > a.) The constructor Mutex() throws an exception indicating that object |> > creation failed.
|> > b.) The object is created in an "invalid" state that can be queried by a |> > method like "bool Mutex::isValid() const". |> > Every other method invocation on the object, for example Mutex::lock(), |> > throws an exception.
|> > Personally, I prefer procedure b.), but I've noticed that all Java |> > classes use a.) Is that a hint to the right design?
|> I don't want to offend you, but (b) is simply idiotic. If the |> creation of an object failed, throw an exception. Anything else |> will cause many lines of error checking code which is just |> braindamaged because exceptions have been introduced to remove |> error checking code from places where they shouldn't be. And |> what else do you want to do later, but throwing an exception ?!?
There is certainly nothing idiotic about b -- there are advantages and disadvantages with all of the possible solutions. In so far as possible, I prefer making the contructors trivial, and requiring the user to call a separate function (with return code) to initialize. One should only go so far with this approach, however. Another approach that is sometimes useful is to pass a reference to a status word to the constructor as a parameter.
Exceptions are extremely expensive, both in run-time and for the programmer -- exception safety requires a significant amount of work, and is to date a not so well understood art. (If you doubt me, see how many of the GotW problems involve exception safety.) For exceptional cases, well, that's what exceptions were designed for; depending on the cost of other remedial solutions (aborting the processes, etc.) and the cost of exception safety in your application and in your programming environment (because the cost of exception safety is largely human), exceptions may be the appropriate solution. The are certainly worth considering.
But there are a lot of cases where "failure" is not exceptional: "file not found" on open would be a typical example. In this case, either provide a separate function for open, or put the object in an invalid state for later querying -- the standard library uses both approaches, and its authors a far from idiotic. The sticky error, which can be tested later, is also the choice of IEEE for floating point errors.
With regards to Java: the Java library throws far too often, and I've more than a few places in my Java code where I've had to work around this. I suspect that one of the reasons is that it is extremely awkward to declare out parameters in Java (see the format and parse functions, for example, which do use out parameters). So either you report an error by return value (not an option for a constructor), or you throw an exception. And since the IO subsystem is not designed to take errors into account, the possiblity of a sticky error has been eliminated as well.
-- James Kanze mailto:James.Ka...@gabi-soft.de Conseils en informatique orientée objet/ Beratung in Objekt orientierter Datenverarbeitung Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
| |> > b.) The object is created in an "invalid" state that can be queried by a | |> > method like "bool Mutex::isValid() const". | |> > Every other method invocation on the object, for example Mutex::lock(), | |> > throws an exception.
| |> I don't want to offend you, but (b) is simply idiotic. | | There is certainly nothing idiotic about b -- there are advantages and | disadvantages with all of the possible solutions. In so far as | possible, I prefer making the contructors trivial, and requiring the | user to call a separate function (with return code) to initialize. One | should only go so far with this approach, however. Another approach | that is sometimes useful is to pass a reference to a status word to the | constructor as a parameter.
These are all pre-exception solutions. They are awkward and error-prone. And it's not just my opinion.
| Exceptions are extremely expensive, both in run-time and for the | programmer -- exception safety requires a significant amount of work, | and is to date a not so well understood art. (If you doubt me, see how | many of the GotW problems involve exception safety.)
I think you are fooling yourself if you think that code written without exceptions is safer than the one with exceptions. All this hair-splitting about exception safety makes a lot of sense for library writers, who must design templates parametrized by classes that might throw exceptions.
Exception safety is a science, unlike the collection of traditional prescriptions about dealing with exceptional conditions. Just run a simple check in any large body of code that doesn't use exceptions. Search for all occurrences of "new" (or malloc). For each occurrence, try to prove that: 1. The result of new is checked for null 2. All program paths lead to the matching "delete" (or free). In particular test all error paths. If your code passes that test, you are an exceptional programmer--no pun intended!
A similar test in an exception-safe code is almost painless (it's localized, unlike the other case).
If you're interested in learning a practical methodology of writing exception-safe code, read my article at http://www.relisoft.com/resource .
| But there are a lot of cases where "failure" is not exceptional: "file | not found" on open would be a typical example. In this case, either | provide a separate function for open, or put the object in an invalid | state for later querying -- the standard library uses both approaches, | and its authors a far from idiotic.
Absolutely! It is very important to distinguish between exceptions and other error conditions. If you haven't checked for the existence of a file and you try to open it--the failure is not an exception. On the other hand, if you did check, or if you are creating a new file, the failure is an exception.
Bartosz
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
In article <86n1qgjizq....@gabi-soft.de> , ka...@gabi-soft.de wrote: > Exceptions are extremely expensive, both in run-time and for the > programmer -- exception safety requires a significant amount of work, > and is to date a not so well understood art. (If you doubt me, see how > many of the GotW problems involve exception safety.)
I don't doubt James' second assertion, that exceptions are not well-understood... although in the C++ community I have observed a very satisfying increase in general understanding of exceptions (if you doubt me, see how many of the responses to the original posting advocate a sensible use of exceptions -- and then go back just two years and read some older posts on the subject!)
Nonetheless, the assertion that exceptions are extremely expensive should not go unchallenged... or at least unqualified. Many compilers will generate far more efficient code (in time, and occasionally even in space) when exceptions are used than when alternative error-handling strategies are employed. This difference will only continue to grow as compilers mature.
Finally, whether or not exceptions are expensive for the programmer really depends heavily on a programmer's familiarity with the tools. I am sure that a programmer unfamiliar with exceptions spends some time getting over the learning curve, but for those of us to who use them every day, to whom exceptions are a currency of our daily work, they are an indispensable _aid_ to productivity. The fact that exceptions allow us to establish and maintain simple class invariants (as alluded to in other posts, and in Bjarne's draft appendix) considerably simplifies writing correct code and entirely REMOVES a layer of flotsam which tends to obscure the problems beings solved in both the error and non-error code paths.
I'm certain this is no different than what happens when learning a new language or library.
-Dave
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
dpou wrote: > Here's my 2 cents. > My reason to avoid throwing from constructors is a potential resource > leak problem. If you have > A::A { > m_p = new char[1024]; > throw 1; > } > A::~A() { > delete [] m_p; > } > void main() { > try{ > A a; > } > catch(...){ > } > } > , the destructor for 'a' will never be called, because the object > hasn't been fully constructed. If you use objects every time you > allocate something, like auto-pointers, then throwing from a > constructor is OK.
Well, if your reason to avoid throwing from constructors is that you want to avoid objects, C++ might not be the best language for you. Have you looked at the current GotW (64, I believe)? Your code shows some of the design problems hinted at. In particular, you can't decide whether new threw, or not.
I'm wondering how you would prevent the constructor from throwing - m_err = 1; instead of throw 1; will still not prevent the memory leak if new throws. Any design that is good enough to prevent the resource leak you fear can use exceptions. Resource leaks can only be avoided if you know exactly which resources are allocated at any moment you are in control, and if that holds true for your design, throwing from a constructor doesn't change that.
Michiel Salters
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Dave Abrahams wrote in message ... >Nonetheless, the assertion that exceptions are extremely expensive should >not go unchallenged... or at least unqualified. Many compilers will generate >far more efficient code (in time, and occasionally even in space) when >exceptions are used than when alternative error-handling strategies are >employed.
That is true, if 1) exceptions are rarely or never actually thrown, and 2) the alternate error handling strategy is propagate-error-code.
The "call exit on error" error handling strategy is, and always will be, faster than exceptions. Much less flexible, sure, but faster.
- Anders
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> I'm curious why you prefer "b"? Is it because you aren't comfortable with > exceptions?
Well, it's just that I've made very unnerving experience with throwing exceptions from constructors a couple of years ago. (Visual C++ even used to produce an internal compiler error when encountering an exception spcification in a constructor...) I just wanted to make sure that this has been proberly standardized in the meantime. Encouraged by the majority of the postings, I tried it again, and this time even VC got everything right. Thanks to everybody for the lively discussion!
|> In article <86n1qgjizq....@gabi-soft.de> , ka...@gabi-soft.de wrote:
|> > Exceptions are extremely expensive, both in run-time and for the |> > programmer -- exception safety requires a significant amount of work, |> > and is to date a not so well understood art. (If you doubt me, see how |> > many of the GotW problems involve exception safety.)
|> I don't doubt James' second assertion, that exceptions are not |> well-understood... although in the C++ community I have observed a |> very satisfying increase in general understanding of exceptions (if |> you doubt me, see how many of the responses to the original posting |> advocate a sensible use of exceptions -- and then go back just two |> years and read some older posts on the subject!)
And if you really think that they are well understood, then just do some recruiting interviews with candidates claiming to be C++ experts. The technical level in this forum is significantly better than that readily available on the market.
|> Nonetheless, the assertion that exceptions are extremely expensive |> should not go unchallenged... or at least unqualified. Many |> compilers will generate far more efficient code (in time, and |> occasionally even in space) when exceptions are used than when |> alternative error-handling strategies are employed. This difference |> will only continue to grow as compilers mature.
Exceptions are, and I believe, will continue to be very expensive when they are raised. This pretty much means that exceptions cannot be used for everyday occurances.
I thought that this much was generally accepted -- exceptions are only for exceptional cases.
I might add that I would expect the run-time price of exceptions to increase as compilers mature -- even today, their only price in execution time when not thrown should be limited to lost optimization possiblities. As optimization techniques evolve, the lost possiblities become more significant. (But honestly, I doubt that they will ever be large enough to make a significant difference in most applications.)
|> Finally, whether or not exceptions are expensive for the programmer |> really depends heavily on a programmer's familiarity with the |> tools. I am sure that a programmer unfamiliar with exceptions spends |> some time getting over the learning curve, but for those of us to |> who use them every day, to whom exceptions are a currency of our |> daily work, they are an indispensable _aid_ to productivity. The |> fact that exceptions allow us to establish and maintain simple class |> invariants (as alluded to in other posts, and in Bjarne's draft |> appendix) considerably simplifies writing correct code and entirely |> REMOVES a layer of flotsam which tends to obscure the problems |> beings solved in both the error and non-error code paths.
I'm willing to believe that this possibility exists. I have yet to see any real documentation concerning program proofs in the presence of the arbitrary flow paths introduced by exceptions.
But I wasn't trying to say that you should never use exceptions. Only that, like everything else, they have a price, and you *should* evaluate what the gain *for* *you* in *your* application, as opposed to what they cost. There is no simple solution which fits all cases.
-- James Kanze mailto:James.Ka...@gabi-soft.de Conseils en informatique orientée objet/ Beratung in Objekt orientierter Datenverarbeitung Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Gernot Neppert wrote in message <387A34B7.A0E3C...@compuserve.com>...
>David Dillard schrieb:
>> I'm curious why you prefer "b"? Is it because you aren't comfortable with >> exceptions?
>Well, it's just that I've made very unnerving experience with throwing >exceptions from constructors a couple of years ago. (Visual C++ even >used to produce an internal compiler error when encountering an >exception spcification in a constructor...) >I just wanted to make sure that this has been proberly standardized in >the meantime.
I don't remember that problem - VC has had so many though its hard to keep track of them all.
VC did have a problem where if the constructor of a new'd object threw an exception it would leak the memory of the object. But, I'm pretty sure that was fixed a while back.
--- David
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
|> | |> > b.) The object is created in an "invalid" state that can be |> | |> > queried by a method like "bool Mutex::isValid() const". |> | |> > Every other method invocation on the object, for example |> | |> > Mutex::lock(), throws an exception.
|> | |> I don't want to offend you, but (b) is simply idiotic.
|> | There is certainly nothing idiotic about b -- there are advantages |> | and disadvantages with all of the possible solutions. In so far |> | as possible, I prefer making the contructors trivial, and |> | requiring the user to call a separate function (with return code) |> | to initialize. One should only go so far with this approach, |> | however. Another approach that is sometimes useful is to pass a |> | reference to a status word to the constructor as a parameter.
|> These are all pre-exception solutions. They are awkward and |> error-prone. And it's not just my opinion.
So back it up with facts. I've yet to see a reasoned opinion that exception safety is trivial. There's a cost analysis involved, and it doesn't always favor exceptions.
|> | Exceptions are extremely expensive, both in run-time and for the |> | programmer -- exception safety requires a significant amount of |> | work, and is to date a not so well understood art. (If you doubt |> | me, see how many of the GotW problems involve exception safety.)
|> I think you are fooling yourself if you think that code written |> without exceptions is safer than the one with exceptions. All this |> hair-splitting about exception safety makes a lot of sense for |> library writers, who must design templates parametrized by classes |> that might throw exceptions.
It makes a lot of sense in applications which are expected to run 24 hours a day, too. Like most of the ones I've worked on in the past.
|> Exception safety is a science, unlike the collection of traditional |> prescriptions about dealing with exceptional conditions.
The problem is precisely that exception safety isn't a science. People like David Abraham are working to bring it there, but it is far from being as mature as the other technologies.
|> Just run a |> simple check in any large body of code that doesn't use exceptions. |> Search for all occurrences of "new" (or malloc). For each occurrence, |> try to prove that: |> 1. The result of new is checked for null |> 2. All program paths lead to the matching "delete" (or free). In |> particular test all error paths. |> If your code passes that test, you are an exceptional programmer--no |> pun intended!
Does a half a million lines count as large. I've worked on projects with that much code, without exceptions, which did exactly what you say.
For that matter, exceptions don't change any of the parameters in this case. Exceptions or no, you still have to prove that there is exactly one delete for each new. And you still have to define a strategy for what to do when memory runs low. (Running out of memory is one case that often does justify an exception. Of course, if you have no backup system, and cannot afford to abort, you don't use dynamic memory anyway:-). But in many cases, the cost of checking *every* allocation is high enough to pay for the extra cost of using exceptions. As I said, it is a cost analysis.)
|> A similar test in an exception-safe code is almost painless (it's |> localized, unlike the other case).
In order to ensure that a piece of code works, you must verify all possible paths of execution. And nothing generates extra paths faster than exceptions.
|> If you're interested in learning a practical methodology of writing |> exception-safe code, read my article at |> http://www.relisoft.com/resource .
|> | But there are a lot of cases where "failure" is not exceptional: |> | "file not found" on open would be a typical example. In this |> | case, either provide a separate function for open, or put the |> | object in an invalid state for later querying -- the standard |> | library uses both approaches, and its authors a far from idiotic.
|> Absolutely! It is very important to distinguish between exceptions and |> other error conditions. If you haven't checked for the existence of a |> file and you try to open it--the failure is not an exception. On the |> other hand, if you did check, or if you are creating a new file, the |> failure is an exception.
I'm not sure about creating a new file, but globally, perhaps we aren't that far apart here. For *any* given error, whether it is an exceptional case or not will depend upon the application. If the open that fails is for a temporary file that you just wrote, it is probably exceptional -- if it is for a filename that the user just gave you, certainly not.
-- James Kanze mailto:James.Ka...@gabi-soft.de Conseils en informatique orientée objet/ Beratung in Objekt orientierter Datenverarbeitung Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
| |> These are all pre-exception solutions. They are awkward and | |> error-prone. And it's not just my opinion. | | So back it up with facts. I've yet to see a reasoned opinion that | exception safety is trivial. There's a cost analysis involved, and it | doesn't always favor exceptions.
I can't explain the whole methodology in one message, but do have a look at my articles on this topic at http://www.relisoft.com/resource .. I've had plenty of experience writing large applications that had to run 24-hours a day for months with no memory leaks. Exceptions + Resource Management solved the problem.
For comparison, all the other subsystems in that product were written using traditional method. At one time we turned on leak detection for the whole project. We quickly had to turn it off, because everybody started complaining about screenfuls of debug dumps after every run. Our subsystem had zero leaks! I don't work for that company any more...
Bartosz
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Gernot Neppert wrote in message <387A34B7.A0E3C...@compuserve.com>... >Well, it's just that I've made very unnerving experience with throwing >exceptions from constructors a couple of years ago. (Visual C++ even >used to produce an internal compiler error when encountering an >exception spcification in a constructor...)
As far as I know, VC still has the problem, though it may be harder to provoke than it was. It can be fixed by adding a redundant semicolon.
class Thing { public: Thing() throw();; // rest of class
};
However, we should distinguish between using exceptions (which is widely accepted by the community and well supported by compilers) and using exception specifications (which remains "controversial").
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
|> |> > b.) The object is created in an "invalid" state that can be queried by a |> |> > method like "bool Mutex::isValid() const". |> |> > Every other method invocation on the object, for example Mutex::lock(), |> |> > throws an exception. |> |> I don't want to offend you, but (b) is simply idiotic. If the |> |> creation of an object failed, throw an exception. Anything else |> |> will cause many lines of error checking code which is just |> |> braindamaged because exceptions have been introduced to remove |> |> error checking code from places where they shouldn't be. And |> |> what else do you want to do later, but throwing an exception ?!? |> There is certainly nothing idiotic about b -- there are advantages and |> disadvantages with all of the possible solutions. In so far as |> possible, I prefer making the contructors trivial, and requiring the |> user to call a separate function (with return code) to initialize. One |> should only go so far with this approach, however. Another approach |> that is sometimes useful is to pass a reference to a status word to the |> constructor as a parameter.
Ooops it seems as if I've posted a troll - I'm sorry.
No, as far as I have understand the original poster, he wanted to throw an exception later anyway, doesn't he ? Or how else do you want to handle an uninitialized mutex ? You can't use it at all, so you have to stop your program. There is no other way.
Throwing an exception at a later time adds error checking code and therefore complexity to all functions of the mutex. I think throwing the exception directly is the far better way in this case.
|> Exceptions are extremely expensive, both in run-time and for the |> programmer -- exception safety requires a significant amount of work, |> and is to date a not so well understood art.
Yep, agreed. Exceptions are a structured utility for error handling. And normally, they should not appear. That is the way I use them, too.
|> But there are a lot of cases where "failure" is not exceptional: "file |> not found" on open would be a typical example. In this case, either |> provide a separate function for open, or put the object in an invalid |> state for later querying -- the standard library uses both approaches, |> and its authors a far from idiotic. The sticky error, which can be |> tested later, is also the choice of IEEE for floating point errors.
Agreed again. Opening a file is the typical case where I didn't liked the exception concept either. It is clear that opening a file might fail, therefore throwing an exception for that is a bad idea: the direct caller of the open() function always wants to handle this error case anyway, often one want to open a different file etc.
Exceptions are better for conditions like "out of memory", which might appear at any point, therefore you don't want to care about them at all points of your program again and again.
|> With regards to Java: the Java library throws far too often, and I've |> more than a few places in my Java code where I've had to work around |> this. I suspect that one of the reasons is that it is extremely awkward |> to declare out parameters in Java (see the format and parse functions, |> for example, which do use out parameters). So either you report an |> error by return value (not an option for a constructor), or you throw an |> exception. And since the IO subsystem is not designed to take errors |> into account, the possiblity of a sticky error has been eliminated as |> well.
Hmm another weakness of Java, yep. But I think most programmers agree that Java is a little bit too simple anyway.
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
In article <86iu11ina6....@gabi-soft.de> , ka...@gabi-soft.de wrote: > |> I don't doubt James' second assertion, that exceptions are not > |> well-understood... although in the C++ community I have observed a > |> very satisfying increase in general understanding of exceptions (if > |> you doubt me, see how many of the responses to the original posting > |> advocate a sensible use of exceptions -- and then go back just two > |> years and read some older posts on the subject!)
> And if you really think that they are well understood, then just do some > recruiting interviews with candidates claiming to be C++ experts. The > technical level in this forum is significantly better than that readily > available on the market.
I'm not surprised! Go back and read what I wrote, James. I said "I don't doubt...that exceptions are not well-understood." Unwind all of the negation and you will see that I was agreeing with you ;)
Of course, we should be clear: by your measure (people who claim to be C++ experts), most of C++ is not well-understood. Some people _do_ understand exceptions, and have been able to describe a discipline for using them effectively. This is better than for many areas of the language (e.g. templates, or even Koenig lookup - where there are subtle issues that haven't been fully explored in any public forum).
> |> Nonetheless, the assertion that exceptions are extremely expensive > |> should not go unchallenged... or at least unqualified. Many > |> compilers will generate far more efficient code (in time, and > |> occasionally even in space) when exceptions are used than when > |> alternative error-handling strategies are employed. This difference > |> will only continue to grow as compilers mature.
> Exceptions are, and I believe, will continue to be very expensive when > they are raised. This pretty much means that exceptions cannot be used > for everyday occurances.
Depends what you mean by "everyday". If you mean "every day", then I think you are wrong ;)
Mileage will vary, of course. In general, throwing a single exception does not result in anything like a human-perceivable delay on any machine I've seen.
> I thought that this much was generally accepted -- exceptions are only > for exceptional cases.
That's pretty much uncontroversial. You wouldn't want to throw them repeatedly from an inner loop. But your original post didn't say "throwing exceptions" was expensive, and could easily have been read to mean that "using exceptions" is expensive.
> I might add that I would expect the run-time price of exceptions to > increase as compilers mature -- even today, their only price in > execution time when not thrown should be limited to lost optimization > possiblities. As optimization techniques evolve, the lost possiblities > become more significant. (But honestly, I doubt that they will ever be > large enough to make a significant difference in most applications.)
The best information I've been able to get from implementors indicates that any "lost optimization" incurred may be a byproduct of the way measurement is done. You can think of a throw as a function call. Calling a function which can throw must be regarded as calling a function which can call another function, for optimization purposes. Throwing an exception directly must be regarded as a function call, for optimization purposes... Of course, this is (probably misinterpreted) 2nd hand info.
This much I _can_ say for sure: any lost optimization can be completely overwhelmed by the elimination of error checks and branches from the non-error code path when exceptions are used. Such code incurs a significant cost on modern processors. Though some effort is made in newer processors to avoid these costs (e.g. speculative execution), avoiding the code altogether will always be a win.
> |> Finally, whether or not exceptions are expensive for the programmer > |> really depends heavily on a programmer's familiarity with the > |> tools. I am sure that a programmer unfamiliar with exceptions spends > |> some time getting over the learning curve, but for those of us to > |> who use them every day, to whom exceptions are a currency of our > |> daily work, they are an indispensable _aid_ to productivity. The > |> fact that exceptions allow us to establish and maintain simple class > |> invariants (as alluded to in other posts, and in Bjarne's draft > |> appendix) considerably simplifies writing correct code and entirely > |> REMOVES a layer of flotsam which tends to obscure the problems > |> beings solved in both the error and non-error code paths.
> I'm willing to believe that this possibility exists. I have yet to see > any real documentation concerning program proofs in the presence of the > arbitrary flow paths introduced by exceptions.
If you want to make programmers _really_ productive, demand that every program come with a formal proof of correctness ;) Seriously, you don't write formal proofs of your programs that don't use exceptions, do you? AFAIK formal proofs are so much work that they can only be applied in toy examples.
Finally, the flow paths from exceptions are not the least bit arbitrary.
> But I wasn't trying to say that you should never use exceptions. Only > that, like everything else, they have a price, and you *should* evaluate > what the gain *for* *you* in *your* application, as opposed to what they > cost. There is no simple solution which fits all cases.
I agree with you there. I encourage you, though, to be sure that your posts on this subject are appropriately qualified, e.g. "for those unfamiliar with exceptions, there is a real cost to learning the idioms", and "throwing exceptions is generally much slower than calling a function", etc. People new to the subject have a hard enough time evaluating the facts without statements which are almost easier to misunderstand than to understand.
-Dave
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
User <v...@dev.null.org> wrote: > [...] > Agreed again. Opening a file is the typical case where I > didn't liked the exception concept either. It is clear > that opening a file might fail, therefore throwing an > exception for that is a bad idea: the direct caller of > the open() function always wants to handle this error > case anyway, often one want to open a different file > etc.
My favorite example is a macro processor that needs to open a file for some reason. If that fails, what can the direct caller of 'open()' do about it but propagate the error upwards in hope some other function will se it that has access to the UI and can pop up a message box? if( !open(...) ) throw Error("Open failed!"); That seems logical to me. And it puts the burden onto the caller of 'open()' where you wanted to remove it from. Now we're talking probabilities: Is it more often that open shouldn't throw or that it should? What ever you think about the statistics -- beeing used to errors beeing 'throw'n at me I prefer the therefor canonical 'catch' over the (forgetable) 'if'.
> [...]
Schobi
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]