|
A False Sense of Security[^] was pretty much an eye opener to me.
Sure, you don't run into these problems very often, but you have to watch out for them 8and seeing them is hard).
|
|
|
|
|
What happens if the copy construction of this object throws an exception? The pop operation fails because the object at the top of the stack cannot be copied (not because the stack is empty). Clearly, the caller does not receive a T object. But what should happen to the state of the stack object on which a pop operation fails in this way? A simple policy would be that if an operation on a stack throws an exception, the state of the stack is unchanged. A caller that removes the exception's cause can then repeat the pop operation, perhaps successfully.
I have yet to write a copy constructor that throws exceptions, and hope never to write one... however, there is the occasional case of the exception-throwing new during copy-construction...
Low-memory errors are a real problem to handle properly. Naive code may try to continue, and fail further down the line during another allocation, or due to not bothering to notice that the memory originally requested doesn't exist. IMHO, the best thing to do is fail quickly back to a stable point in the app, where perhaps the user can be notified and existing work preserved until additional resources are freed up.
Of course, none of that addresses the issue: we've still lost the top of the stack. Frankly, this doesn't concern me as much as it probably should - i never pass heap-allocating objects by value unless (like CString) they have a copy-on-write or (like auto_ptr) ownership transfer behavior such that they can effectively be treated as stack objects. And i consider stack overflow a catastrophic failure in any context.
But i agree - it is a concern, and can't be ignored completely. Still, exceptions are an error-handling mechanism, and when left to that role i think they do fairly well. The important thing, always, is to handle errors only at the layer where they can be effectively dealt with. Sometimes, this means crashing and burning - i hate to say it, but it's true: some errors are such a severe indication of broken logic that it is dangerous to let the program continue. Exceptions work admirably for this as well...
----
It appears that everybody is under the impression that I approve of the documentation. You probably also blame Ken Burns for supporting slavery.
--Raymond Chen on MSDN
|
|
|
|
|
Shog9 wrote: I have yet to write a copy constructor that throws exceptions
Fair enough - but (;)): That's exactly the problem when you write generic utility templates: you don't know nothing who is going to use your code with what type. That's all no problem if the documentation states "the copy constructor of T may not throw an exception", but frankly, the best documentation to hope for the constructor itself is "creates a copy of rhs".
The main problem with C++ is that it's not easy to "fall back to a stable point", if your heap is corrupted, you are done.
Shog9 wrote: i never pass heap-allocating objects by value unless (like CString) they have a copy-on-write or ownership transfer
sane
Shog9 wrote: (like auto_ptr)
insane
Anyway, many bad things can be said about threads, and still I wouldn't argue against them being very useful. it's just no beginners material, and the same goes for exceptions.
May peeves are less the complexity itself but thatthey are sold as a panacea, and that local handliing is very verbose (but the Likely<T> stuff by Andrei/Petru look tempting for that)
|
|
|
|
|
peterchen wrote: The main problem with C++ is that it's not easy to "fall back to a stable point", if your heap is corrupted, you are done.
Well, that's probably true of most languages / platforms. C++ just makes it a bit easier to corrupt your heap...
peterchen wrote: and that local handliing is very verbose (but the Likely<t> stuff by Andrei/Petru look tempting for that)
Agreed.
----
It appears that everybody is under the impression that I approve of the documentation. You probably also blame Ken Burns for supporting slavery.
--Raymond Chen on MSDN
|
|
|
|
|
In hasty response, sales of exception-safe code before and after Sutter-era journalism did nothing to prove such code is:
a) around aplenty
b) performs better
c) is more maintainable
d) appropriate for component-based development in C++
While I am slightly worried to see ATL roots here acknowledging the fact exceptions can produce more readable and maintainable code, I must agree with it if you look at that fragment (readable, maintainable), word by word. But not any further than that.
All I can do is give my short and uninformed story:
For one, a lot of effort went into exception-less STL and platforms that had no compiler or runtime support. Same goes for ATL and WTL I guess.
The following one is not on checked access, but on checked concepts, one of them being iterators are priceless as they can report subtle errors no exception or errorcode-based code can resolve - logic bugs.
Writing service or system software was done in C (until Vista I guess), and huge body of work went into it. People still argue on specification lists and what if any of exception-related information should be in the metadata.
Lastly, no exception hype or book or next modern mechanism can protect against exceptional circumstances of OS, security, network or any other type of 'integrity' failure. Attempting to use C++ as a tool for transactional programming (be that replication work before moving on to compiler team or not), without expecting C like and MTS like interfaces is, in my mind, a good waste of time.
If you are attempting to save your application state, than you might as well do a differential backup, continuous backup, pre-allocate storage, and do whatever you were going to do with exceptions because they will not help you much more once you hit the 'exceptional circumstances'.
Heard of : 'Program encountered an error. Please save your work', only to see the Save operation initiate a crash of the system?
Exceptions do not improve availability either, and I could argue they disable plenty of optimisations new (re:copy of old) hardware architectures are providing.
Examples:
MS Word crashes with or without exceptions.
IE too.
SQL Server reports rejection on overload, do you as a client bomb out too?
Your OS becomes unresponsive any time it deals with any good file manipulation, do you bomb out?
And who do you bomb out to?
Simply the next 'manager' that is very likely to bomb out, and so the story goes all the way down to halt or blue screen (or your system requires administration anyway, like restart).
That is how most software works, and exceptions are just an implementation detail that makes a lot of overhead in service-based or OS software.
Having criticised exceptions for time I have for the discussion, I can see a good use to them if you are looking out for integrity hype that exceptions never achieved. The best possible use I can see to them is in deep 'inner scope' of a function, making programming/interfacing to 3rd party components clean and lazy (as in simplified error checks).
The fact is if you do not understand a large number of conditions or values you might be hit with, or have provisioned for them to a 'good enough' extent, you are more likely to have an event tracing use rather than an exception use in your code (see the trend in all software overwhelming your Event Log with information).
Using a catch all clause can help against further corruption sure, but if you know those values why not record them or better handle them so your system is in maintenance mode for you to see, rather than having it obscured in a complex 'unwinding interaction'.
Besides, you know it all ducks when those slow CLR dialogs appear, especially on floating point arithmetic, bad XML, and file manipulation.
And, quite frankly, ‘The Power Of None’ seems like another attempt at template masturbation while another X systems and runtimes are on your path, on a daily basis, on a another piece of unreadable Martian writing.
Less code is better, but less code is ‘other’ services too, not just exceptions.
Example: what NX bit did for C code.
Sincerely,
6
-- modified at 19:19 Tuesday 17th April, 2007
|
|
|
|
|
I used to use the "reserved return value" method, but I've converted to using HRESULT s for the retval, and any additional output is returned through reference parameters. Using a consistent retval system is actually easier, because the caller doesn't have to think "now does this function return 0 or -1 (or NULL or INVALID_HANDLE_VALUE ) on error?" when using my functions. Every retval can be tested with SUCCEEDED /FAILED .
|
|
|
|
|
Nothin' i hate worse than cluttering up my beautiful code with all sorts of error checking.
But yeah, unless there's a way of recovering from an error, i prefer to throw an exception and let the UI deal with reporting the problem.
----
It appears that everybody is under the impression that I approve of the documentation. You probably also blame Ken Burns for supporting slavery.
--Raymond Chen on MSDN
|
|
|
|
|
|
Many years ago I found a desent recursive parser (C code) that used longjmp() . The first thing I did was eliminate the need for it by using return values, because I considered that a poor solution to the problem and have never used longjmp() in any of my code.
Note: Exceptions where not an option, at the time.
INTP
"Program testing can be used to show the presence of bugs, but never to show their absence."Edsger Dijkstra
|
|
|
|
|
With C++ you do not have to. I learned this trick it long time ago
#define HR(f) {HRESULT hr = f; if( hr < 0 ) return hr;}
then any call of any function will be
HR(CreateFile(..));
That will automaticly unwind your stack like exception does.
|
|
|
|
|
At some point, you still need to manually check the return code and interpret it. Call GetLastError() , throw together some context based on what you needed the file for or where you were trying to create it.
Personally, i'd just as soon keep all WinAPI plumbing in one spot, extract as much context as possible, and then pass it on. Whether that involves throwing an exception, setting a flag, or a Dunn-esque combo of return values and reference parameters depends on the needs of the caller.
----
It appears that everybody is under the impression that I approve of the documentation. You probably also blame Ken Burns for supporting slavery.
--Raymond Chen on MSDN
|
|
|
|
|
Michael Dunn wrote: Exceptions are evil
Now, that's a bit too strong, I think. Exceptions are useful in exceptional (pun intended) situations. The main problems I see with them are:
1) Using exceptions for normal program flow - for instance to avoid using goto when breaking out of a nested loop.
2) Using exceptions without applying exception safety coding principles, which leads to all sorts of resource leaks and objects in undefined state.
In general it is a very good idea to read Sutter's Exceptional C++[^] (even for programmers who use other languages) to learn how to use exceptions in a safe and productive manner.
|
|
|
|
|
Generally and especially for critical errors I prefer logging a clear-cut message to the event log in addition to returning a predefined error code.
"Silence will create respect and dignity; justice and fair play will bring more friends;
benevolence and charity will enhance prestige and position; courtesy will draw benevolence;
service of mankind will secure leadership and good words will overcome powerful enemies"
Ali (Peace be upon him)
|
|
|
|
|