3 ms·
Don't really agree, this seems too general? It's a matter of preference, what level you're working on and of what is possible. For example you're writing C++ wh
by stinos 11y ago
Don't really agree, this seems too general? It's a matter of preference, what level you're working on and of what is possible. For example you're writing C++ which is going to be wrapped in a C-style api then yes you are going to need those error codes. If you are writing an application using some C++ api with well-defined exceptions then using them might lead to much nicer code. Consider some function in main() which takes care of a ton of initialization; I just happen to prefer
try
{
MethodA();
MethodB();
MethodC();
}
catch( const FooException& e )
{
//show e
return 1;
}
catch( const BarException& e )
{
//show e
return 1;
}
over
auto resulta = MethodA();
if( FAILED( resulta ) )
{
//show result
return 1;
}
auto resultb = MethodB();
if( FAILED( resultb ) )
{
//show result
return 1;
}
auto resultc = MethodC();
if( FAILED( resultc ) )
{
//show result
return 1;
}
they don’t work across modules
A problem which fades away if you build all code using the same compiler and build settings, which is a good idea anyway (there's not much which works across modules when mixing e.g. debug and release builds). I've written a lot of C++, and misbehaving across modules is like the one thing I didn't have problems with :]
- Const-me 11y ago1. Harder to maintain. Your colleague will change MethodB so it now throws an ExceptionB(), and your code will crash with unhandled exception = segfault. With error codes, your colleague may return any FAILED code she finds adequate. As long as you have a standard way of showing messages, the caller doesn’t need to change a single line. 2. You can greatly simplify your return codes example with a macro, e.g. #define CHECK( hr ) { HRESULT __hr = (hr); if( FAILED( __hr ) ) return __hr; } Then you will be able to handle them in the upper level. Also, by changing this macro to slightly more complex variant you can very easily log failed operations (remember that __FILE__, __LINE__, #hr, etc.) “if you build all code using the same compiler and build settings” — fine, what about using other people’s libraries you can’t or don’t want to compile? Like OS-provided API, CRT, middleware, etc? Also, what happens with your project code style consistency if you’ll decide to replace 3rd party component (that unlikely uses exceptions) with in-house, or vice versa? P.S. I’ve written a lot of C++ as well, I’ve been developing commercial software since 2000. My experience tells me if you’re going to achieve good quality of your product, it’s seldom sufficient to just print messages to stdout or MessageBox an exception message. Depending on what exactly happened and what the code was doing when something failed, it may be necessary to do something more complex that needs rich execution context. Like write stuff to logs, send error details to the client over a network in the response, close some windows, invoke a caller-provided error handler, etc. You don’t have that context where you catch() them.
- stinos 11y ago1. Fair point, though in actual code at a top level (which the example shown was intended to be - as I'm not advocating one must use exceptions everywhere) there would be a catch( const std::exception& ) so it is not an issue. 2. Indeed you can what about using other people’s libraries you can’t or don’t want to compile? I do want to compile them, or if I can't then either it is not a problem (at least I never had problems with OS provided APIs and CRTs which would give such problems because they are designed to circumvent it) or I might not want to use the libraries (never occurred to me, maybe I'm lacking experience or the particular applications I wrote just never gave me the chance of having to be in such situation). Also, what happens with your project code style not really an argument, same can be said for switching to a library which does use exceptions regarding PS: most of my/our applications have so much logging the lack of execution context is usually not a problem. In addition to that in those rare cases where things go completely berserk on Windows we'd use full minidumps. Not sure if that is what you mean with execution context though as I don't see how logging/sending error details/other things you mention would be handled differently when using exceptions vs error codes.
- kabdib 11y agoGo read one of Herb Sutter's "Exceptional C++" books. Okay, just read the first one. If you don't close the book and reflect, "I am never writing this shit," Herb didn't do his job. Writing exception-safe code in C++ is very hard. Depending on another module's authors to get their C++ exception handling right is the road to madness. In the example above, the FAILED clauses clearly handle all the failures. In the exception handling example it is not clear if all the failures are caught, or if they are more that are meant to be caught at higher levels, or perhaps exceptions were forgotten. It becomes very difficult to reason about control flow because exceptions distribute it across the program and over time. Someone might add another exception: Oops, you didn't handle FileNotFoundException and your program bombs. You add a new exception that seems reasonable, but you wind up changing a hundred places in your source code (... and your callers! hope you have good customer support). Exceptions are exceptional, they should not be used to return indications of failure. Exceptions should be used when it's lights-out important that something Really Bad be handled or the program will be killed. Most C++ systems I've worked with catch an exception near the top, do some diagnostics, and either tell the use "wups" or attempt to restart. A "FileNotFound" exception from an open() function is just colossally stupid. I don't have a nicer way of saying that. If I saw code with this pattern in a project that I was on, I would remove it and make sure it didn't happen again.
- stinos 11y agoA "FileNotFound" exception from an open() function is just colossally stupid. Yes it is, and my example wasn't about such functionality anyway
- exceptthat 11y agoIf you don't close the book and reflect, "I am never writing this shit," Herb didn't do his job. The same Herb who said Prefer to Use Exceptions to Report Errors? (which makes no sense btw, just like saying to never ever use them) Depending on another module's authors to get their C++ exception handling right is the road to madness. Wait, so we should just forget about STL/boost/.. and reinvent all wheels? Or maybe just all code - depending on another module's authors to get their error code handling right, as in not ignoring all of them, is also madness. You add a new exception that seems reasonable, but you wind up changing a hundred places in your source code (... and your callers! hope you have good customer support). That is just not how proper code using exceptions gets written, ever. Anyone can make up similar horror stories for error codes (you are checking if HR is FILE_NOT_FOUND or FILE_NOT_ACCESSIBLE but suddenly the author changed the name into FOOFILE_NOT_FOUND and now you wind up changing a hundred places in your source code) Callers know what exceptions they can handle (if they don't the code is crap anyway) and handle those. If a caller wants to provide a strong guarantee the caller catches everything and nothing is forgotten. Everything else is truly exceptional and bubbles up, eventually to the top like all most C++ systems you saw.