A C error handling style that plays nice with C++ exceptions
blog.sduto.it
blog.sduto.it
It's also worth mentioning that it's pretty easy to create the Error object on the stack, such than an error_free() function isn't necessary, but strings become a bit more messy in that case (like needing string interning or forcing all error strings to be static).
pubby8 May 3, 2014 at 10:07 PM
Good article, but I'm guessing that using more than one
ThrowOnError per statement will lead to std::terminate.
e.g. in seemingly reasonable code such as:
std::cout << libfoo_create_widgets(1, &c1, ThrowOnError()) << libfoo_create_widgets(2, &c2, ThrowOnError());
Does C++ not specify an evaluation order for chained stream insertion operands? It seems to me as a C programmer that the first ThrowOnError should be destroyed before the second one gets created.Remember "<<" is just that, an operator.
Only && and || have a mandated evaluation order.
It's like the author knew it was a bad idea too (he put noexcept(false) on the destructor; without which in C++11 the program terminates immediately when an exception is thrown from destructor).
If there's some way to avoid terminating when there's a double exception in the destructor, that would be good to hear!
One simple way I can think of is to reuse the same variable instead.
ThrowOnError throw_on_error;
std::cout << libfoo_create_widgets(1, &c1, throw_on_error) << libfoo_create_widgets(2, &c2, throw_on_error); NSError* error = nil;
[object doSomething: foo error: &error];
if(error){
}
I find exceptions to be rather overkill for most error type problems to begin and with the ObjC system it's easy to ignore errors that may not be critical. [object doSomething: foo error: nil];With a suitable modification, the mentioned example would have to be changed from...
libfoo_widget_container_t container = NULL;
libfoo_error_details_t error = NULL;
if (libfoo_create_widgets(12, &container, &error) != libfoo_success) {
printf("Error creating widgets: %s\n", libfoo_error_details_c_str(error));
libfoo_error_details_free(error);
abort(); // goodbye, cruel world!
}
...to... libfoo_widget_container_t container = NULL;
libfoo_error_details_t error = NULL;
libfoo_create_widgets(12, &container, &error);
if (LIBFOO_IS_BAD(error)) {
printf("Error creating widgets: %s\n", libfoo_error_details_c_str(error));
libfoo_error_details_free(error);
abort(); // goodbye, cruel world!
}
where LIBFOO_IS_BAD() would be a macro or inline function inspecting the error object/struct, and might be something like #define LIBFOO_IS_BAD(error) ((error) && (error)->errno != 0)
Cutting out the cruft, it's basically what you had suggested to pre pretty Objective-C style ;-) /* your example */
NSError* error = nil;
[object doSomething: foo error: &error];
if(error){
}
/* article */
libfoo_error_details_t error = NULL;
libfoo_create_widgets(12, &container, &error);
if (LIBFOO_IS_BAD(error)) {
}
EDIT: The linked article already mentions that in the example, error would only be updated if the function returned something unlinke libfoo_success, so one could directly convert to your favourite style keeping these semantics![Core C++ library] -> [stable C interface]
[Core C++ library] -> [stable C++ interface]
That would avoid extra overheard in the last case.