Thanks for the long response, Ted. Although I disagree with most of it, I appreciate your time. Some of the points you have made are slightly unclear: On Wed, Mar 19, 2008 at 5:04 PM, Ted Byers <r.ted.byers@xxxxxxxxxx> wrote: > The following code strikes me as an abuse of exception > handling. Exceptions ought to be reserved for > unpredictable, rare error conditions. How would you handle predictable, common error conditions, then? And what do you consider to be unpredictable and rare? Going back to the XML example (since it's an easy one to build on), let's say I have a document structured like this: <root> <something> <value> <data> </data> </value> </something> </root> If I was writing code to parse that, and found "root", then "something", then "value", but not "data", I would call that a rare error. Also the only way to really recover from it is to let the user know what happened, and to leave the program in a valid state or terminate it. Using exceptions that way provides for both in a very simple way. In my examples, for simplicity, I threw a Something() -- but associating error messages with exceptions, and a good exception inheritance structure, makes error handling and reporting very easy (e.g. throw EDocumentFormatError(__FILE__, __LINE__, "Data node is missing from file.")). Take Java as an extreme example of the use of exceptions. > Unless you are > doing ONLY batch processing, you want your interface > to be as user friendly as possible. Therefore, you > want to, and can, know precisely what conditions would > result in your call to, say, xmlReadFile failing, and > can test for it. If your test(s) for such conditions > that could lead to failure identifies a potential > problem, you can notify your user of the problem and > prompt him to take corrective action. By this I assume you mean ask libxml for a clear error string and somehow display it to the user, correct? If that is the case, I agree. I hate receiving error messages such as "Error: Operation failed", and so I do what I can to not display vague messages like that to the user either. I did leave all that out of my example. However, including the error message in an exception is an extremely clean way of passing that information back to the caller. What would your alternative be? Returning error codes from functions becomes messy, and setting global error strings with functions such as GetLastErrorMessage() (or whatever, you get the idea) comes with its own set of problems. > Your error > condition, then, doesn't arise. I am not sure what you mean. If a file does not exist and therefore can not be opened, notifying the user of the error does not cause the file to exist. > User error WRT data > input is common enough that it is much better to test > for all errors that you can test for, and prompt the > user for corrective action than it is to just throw > exceptions willy nilly every time a statement doesn't > give you what you wanted. Agreed. I don't see what is willy nilly. In this particular example, I have an XML file that contains some data that I need to load. The XML file must adhere to a very specific structure that has been defined elsewhere. When the user chooses to load the file, the file must either be 100% compliant with the defined structure, or it will fail to load. I have no desire to prompt the user with message boxes such as "Sorry, but the X data element was missing from this data file, would you mind telling me what you think the value should be so I can recover and continue?" A user would not be able to answer that question in my case anyway. Instead, if the file has a slight problem (it should not, as the files are not hand-generated), I want to notify the user that the file could not be loaded. Of course, I would provide them with a reason why the file could not be loaded, but it is not always necessary, or even possible, to allow the user to intervene and correct an error condition themselves. Therefore, in the XML example, if any one of those operations fails, the entire load operation *should* fail, and therefore every operation warrants an error return on failure. In this case, exceptions are a great error return, because they can store a lot more information than, say, returning an integer from a function. In fact, this is *precisely* what exceptions are designed for. > To use a trivial example, suppose your code does > mathematical analysis and you routinely evaluate a > quotient "x / (a - b)". You KNOW going in that you'll > encounter a divide by zero error condition either if a > = b or both 'a' and 'b' = 0. Instead of just letting > the error happen, you test for the possibility of the > error condition, and when detected you terminate the > affected call, ... I agree completely. This is very reasonable. > ...returning control to a function that > prompts the user for corrective action and handle the > result. This seems like a reasonable way to do that: class EDivideByZero : public Exception { ... }; int DoTheMath (int x, int a, int b) throw (EDivideByZero) { if (a == b) throw EDivideByZero("Divide by zero: A must not equal B"); else return x / (a - b); } void DoWhatever () { try { DoTheMath(4, 2, 4); } catch (Exception &e) { DisplayTheError(e.TheMessage); } } This notifies the user of the problem, and this also allows DoWhatever() to handle errors without ever having to have knowledge of what the error was. It is up to the source of the error to describe the error. > If a programmer working for me showed me code like > that which you show here, I would probably send him > back to the drawing board for there is no evidence of > any analysis of error conditions and possible error > prevention. I am not sure what you mean. There is analysis of error conditions -- all operations are checked for errors. Errors are not left unhandled. If by no "error prevention" you mean that the user is not given any notification of *what* operation caused the error -- well I assure you that's because I left out specific error messages in my example, since I was asking about SEH and they weren't relevant. > Such a failure guarantees a less than > adequate user experience, and significant wasted user > time, squandered on trying to figure out why the > program didn't do what the user expected it to do. Much of what you say is based on the fact that my example had no specific error messages. Given that, everything you say is completely reasonable. However, in the actual code, I do provide error messages, so most of the issues you are talking about are not problems. In fact, I even include the file name in the error messages. <g> > > If my goal is to reduce the amount of coding I have > > to do, it is far > > easier for me to duplicate the cleanup code than to > > go and write a > > bunch of small C++ wrapper objects with automatic > > cleanup that I can > > use interchangeably with the libxml2 data types. > > > This doesn't make sense. If you can write cleanup > code, regardless of which library you're using, you > can do so efficiently using RAII. You can't use the > existance of one badly written library or another as a > rational for poorly structuring your own code. I am not attempting to rationalize poor structuring of any code. > If for > some reason, you don't like existing wrapper libraries > for libxml2, then roll your own. Trust me, your > preference for copy and paste duplication of your > "cleanup" code will come back to bite you at a most > inconvenient moment. Your code will bloat as you > develop it further, eventually becoming a maintenance > nightmare. Yes, I know this. This is precisely why I came here to ask about SEH in GCC... SEH is a feature in other compilers that I use precisely to prevent the bloat. GCC did not provide it, and now I am looking for an alternative. You are preaching to the choir, my friend. > Trust me, I have worked on projects that, > efficiently coded, had in excess of half a million > lines of code, and when a project gets that big, the > last thing you want to do is refactor to remove code > duplication. It is much better to get it right the > first time through that to have to fix it after it has > become a bloated monster. Again you are preaching to the choir. I promise. :-) > Yes, both do. std::auto_ptr and boost::shared_ptr, > and there are variants of each used for pointers to > arrays. You do have to make sure you use the right > version of each, for each pointer you're replacing. > But if you have to use functions like 'xmlFree' to > properly clean up, there is no option other than to > write your own class that invokes such functions in > its destructor. Thanks. Actually, it seems that the boost::shared_ptr lets me use xmlFree without writing my own class to do it -- see me22's previous reply -- which is a perfect solution to my issue of duplicating cleanup code. > The smart pointers only invoke delete > on the enclosed pointer at the right time. They can do other things besides delete. > Even so, > writing a wrapper class for a resource you have to > manage remains trivially easy, and much more > maintainable than your copy and paste approach. Writing a wrapper class is not necessary as long as your cleanup function takes only one parameter (such as xmlFree), see boost::shared_ptr. However, it is definitely more maintainable than my copy and paste approach. > And > if you must keep your resource on the heap rather than > on the stack, you would still use your custom resource > class WITH one of the smart pointers. You can just use the smart pointers directly. > > HTH It is certainly food for thought. I do appreciate your reply. > > Ted Jason