Code reuse in exception handling - c++

I'm developing a C api for some functionality written in C++ and I want to make sure that no exceptions are propagated out of any of the exported C functions.
The simple way to do it is making sure each exported function is contained in a:
try {
// Do the actual code
} catch (...) {
return ERROR_UNHANDLED_EXCEPTION;
}
Let's say I know one exception that is often missed inside the C++ code is std::bad_alloc and I want to treat it specially I'd write something like this instead:
try {
// Run the actual code
} catch (std::bad_alloc& e) {
return ERROR_BAD_ALLOC;
} catch (...) {
return ERROR_UNHANDLED_EXCEPTION;
}
Is it possible to decompose this in some clever way so that I can globally treat some errors differently without adding a new catch statement for the exception handler around every exported function?
I'm aware of that this is possible to solve using the preprocessor, but before going down that road, I'd make sure there is no other way to do it.

You can use only one handler function for all possible exceptions, and call it from each or your API implementation functions, as below:
int HandleException()
{
try
{
throw;
}
// TODO: add more types of exceptions
catch( std::bad_alloc & )
{
return ERROR_BAD_ALLOC;
}
catch( ... )
{
return ERROR_UNHANDLED_EXCEPTION;
}
}
And in each exported function:
try
{
...
}
catch( ... )
{
return HandleException();
}

There already is a good answer. But just FYI, its called 'exception-dispatcher' idiom, see C++ FAQ.

What about:
try{
//Your code here
} catch(std::exception e)
{
return translateExceptionToErrorCode(e);
} catch(...)
{
return UNKNOWN_EXCEPTION_THROWN;
}

Jem answer is a little more simpler than this solution. But it is possible to substitute the use of a preprocessor macro with the use of templates. Something like this (more refinements you could made):
template <class T, void (T::*FUNC)()>
class CatchWrapper
{
public:
static void WrapCall(T* instance)
{
try
{
(instance->*FUNC)();
}
catch (std::bad_alloc&)
{
// Do Something 1
}
catch (std::exception& e)
{
// Do Something 2
}
catch (...)
{
// Do Something 3
}
}
};
class Foo
{
public:
void SomeCall()
{
std::cout << "Do Something" << std::endl;
}
};
int main(int argc, char* argv[])
{
Foo i;
CatchWrapper<Foo, &Foo::SomeCall>::WrapCall(&i);
return 0;
}

Do not ever use catch(...), unless you plan on more or less immediately re-throwing. You will certainly lost any error information you might have had to help you figure out the cause of the error.
I like your second scheme a little better - catch a known set of exceptions, ideally because they are the only ones your code will throw, and let the rest through - allowing the app to crash is possibly the best thing to do since you have invoked unknown behaviour it is best to "crash responsibly".

It would be a shame to loose error information at the language boundary. You really should try to translate all exceptions into an error code usable from C.
How you do it really depends on what your exception classes look like. If you control your exception class hierarchy, you can ensure that each class provides a translation using a virtual method. If not, you may still find it practical to use a translator function and test the types of the 'std::exception'-derived exception it receives to translate it into an error code, much like Jem suggested (remember: thrown exceptions will hurt performance anyway, so don't worry about the translation being slow).

Related

Generic logger vs. exception pattern

Consider a class foo which has one or more functions which can report failure either through a logger or by throwing an exception if no logger was provided:
struct logger
{
// ...
};
struct foo
{
void set_logger(std::shared_ptr<logger> logger) { m_logger = std::move(logger); }
bool bar(const std::filesystem::path& path)
{
// Check path validity
if (not std::filesystem::exists(path) {
if (m_logger) {
m_logger->warn("path does not exist.");
return false;
}
else {
throw std::runtime_error("path does not exists.");
}
}
// Some random operation
try {
// Do something here that might throw
}
catch (const std::exception& e) {
if (m_logger) {
m_logger->warn("operation bar failed.");
return false;
}
else {
throw e;
}
}
return true;
}
private:
std::shared_ptr<logger> m_logger;
};
This does not only look ugly but is extremely error prone and as more functions are added to foo code will be repeditive.
Is there any kind of pattern or paradigm to abstract this logic away? Some kind of wrapper template I can construct to use inside foo's various functions when error reporting is needed?
Anything up to C++20 would be acceptable.
Is there any kind of pattern or paradigm to abstract this logic away? Some kind of wrapper template I can construct to use inside foo's various functions when error reporting is needed?
One thing you could do is to simply remove all the else { throw... } code and provide a default logger that throws an exception containing the logged message. If the client provides a different logger, fine, your code will use that; if not, it uses the default one. This scheme eliminates about half your error handling code and simplifies the flow while providing the same behavior, which seems like a positive outcome.
It's important to remember that logging a message is different from throwing an exception: it's often useful to be able to log a message that doesn't stop the flow of the program. So be sure to give your logger class methods that log without throwing as well; you might use a different log level for messages that are equivalent to exceptions.
Since your error case handling seems to follow the same structure, you could add a simple function that will do just that:
bool log_or_throw(logger * logger_, std::string const& message, std::exception const& exception) {
if (logger_) {
logger_->warn(message);
return false;
}
else {
throw exception;
}
}
And then you can change your error handling to a single line, probably making the flow a lot more readable:
if (not std::filesystem::exists(path) {
return log_or_throw(m_logger, "path does not exist.", std::runtime_error("path does not exists."));
}

How to organize dozens of similar try-catch blocks?

I have external interface, let's say with 20 similar methods. Each can throw anything.
So, I have 20 methods looks like:
void Call3Wrapper(int& important_parameter)
{
try
{
external_namespace::IExternal::Call3(important_parameter);
}
catch(external_namespace::Exception& ex)
{
LogIt(ex, "Call3");
throw mynamespace::MyException(ex);
}
catch(std::exception& ex)
{
LogIt(ex, "Call3");
throw mynamespace::MyException(ex);
}
catch(...)
{
LogIt("Unresolved exception", "Call3");
throw mynamespace::MyException("Unresolved exception");
}
}
And same for each Call1-Call20 (calls with different parameters).
Such as:
void Call7Wrapper(std::string& important_parameter)
void Call12Wrapper(bool& important_parameter, double&
important_parameter2)
...and etc.
I have nice function LogIt for all those cases, and our own type MyException, that handles all those cases also.
And all those 20 (40, 60) function's bodies looks ugly, because 90% of code is exactly similar try-catch checks. And a developer will die when he will need to fix anything same in all of them...
Does there exists a method / practice how to organize it less ugly way?
Something like lock-unlock-idiom in constructors&destructors, but for try-catch?
I definitely don't want to use #define CALLS_CATCH_BLOCK(call_name) ...
Maybe you can templatize the wrapper and call it via function objects:
template<typename CALLABLE_T>
void CallWrapper(CALLABLE_T callable, const char* name)
{
try
{
callable();
}
catch(external_namespace::Exception& ex)
{
LogIt(ex, name);
throw mynamespace::MyException(ex);
}
catch(std::exception& ex)
{
LogIt(ex, name);
throw mynamespace::MyException(ex);
}
catch(...)
{
LogIt("Unresolved exception", name);
throw mynamespace::MyException("Unresolved exception");
}
}
Then you can use std::bind to create callable object with parameters, for example:
CallWrapper(std::bind(&external_namespace::IExternal::Call3,
std::ref(important_parameter)),
"Call3");
(or boost::bind/boost::ref for older compilers)
Note that the compiler will still generate an instantiation of the template for each different CALLABLE_T type, but you do not need to repeat the code.
Also note that this way you can also call and handle member functions of classes etc.
If this is to be used by an API interface, you might still need to create the separate methods, but call the templated wrapper internally instead of repeating the exception handling code.

make_shared in a try catch - scoping issue

I need to allocate memory, but I would like to do this in a try/catch, but that introduces a new scope, in which the variable is then not available once I'm out of the try-scope. What's the best way to solve this?
try {
auto something = std::make_unique<SomeClass>;
}
catch (std::bad_alloc) {
...
}
// ... lots of code I don't want to include in the try/catch-scope.
something.callSomeMethod();
How to I go about solving this?
There is a specific reason why what you are doing shouldn't work. If the code you wrote worked the way you wrote it, then you would be calling callSomeMethod() on a null object. The right way to do it as Benjamin Lindley said, is to put that code in your try block. That way the variable is in-scope but the method call will only happen if there was not a bad alloc that threw an exception.
For posterity, and in case you needed to do something else in your try block that would not result in an invalid pointer (because, as has been mentioned there is a reason what you're trying to do doesn't work). If you're trying to do something else and still want to execute your operations on something afterward, the following code will do what you want:
#include <iostream>
#include <memory>
#include <utility>
using namespace std;
int main()
{
class SomeClass { public: int a; void callSomeMethod() const {} };
std::unique_ptr<SomeClass> something{};
try {
something = std::move(std::make_unique<SomeClass>());
// operation that might throw other_exception
}
catch (const other_exception& e) {
std::cout << "bad" << std::endl;
}
// ... lots of code I don't want to include in the try/catch-scope.
something->callSomeMethod();
return 0;
}
As other answers have mentioned, your code should generally be within the try/catch block, since it doesn't have any meaning if the exception is caught. I'm not sure what your reason is for not wanting to include the code in the try/catch, since you're implying something.callSomeMethod() depends on lots of code, and lots of code depends on std::make_unique. If lots of code isn't dependent, you can delay std::make_unique until after lots of code.
I think it might be worth clarifying, the purpose of exceptions is to abort and handle an exceptional situation. The exceptional situation is that execution of following code can be impacted. So, any code that would be impacted, or transitively code that depends on it, should be included in the try/catch block. This is the minimal scope, by definition, and it's the scope you should use. Nothing more, nothing less.
Sometimes the code to handle an exception can be shared across functions that throw exceptions, but it's still generally best to narrow the scope and write the necessary specific handling code for each one.
It might be worth noting that almost nothing can be done for std::bad_alloc, so it's generally not an exception worth catching. Also, you should generally catch exceptions by reference unless you have a reason to do otherwise. So, your code should look something like this...
try {
auto something = std::make_unique<SomeClass>;
// ... lots of code I don't want to include in the try/catch-scope.
something.callSomeMethod();
}
catch (std::exception& e) {
// you dun goofed...
}
If you really must use something outside the try/catch block (and no, you really mustn't, but if you insist...) then it's a good idea to make it impossible to give yourself a segfault.
calling a method on a null unique_ptr is a sure way to disaster, plus the initialisation of the unique_ptr requires an un-necessary memory allocation.
Another way is to use boost::optional :
#include <iostream>
#include <boost/optional.hpp>
using namespace std;
int main()
{
class SomeClass { public: int a; void callSomeMethod() const {} };
boost::optional<SomeClass> something{};
try {
something = SomeClass();
// operation that might throw other_exception
}
catch (const std::exception& e) {
std::cout << "bad" << std::endl;
}
// ... lots of code I don't want to include in the try/catch-scope.
if (something) {
something.get().callSomeMethod();
}
return 0;
}

C++ error number allocation - are there any accepted standards?

Are there any conventions about which error numbers I should use in my C++ code?
Do I start at 1 or should I pick a high number and go from there?
An example was requested, so here it is:
#define ERR_EVERYTHING_IS_WRONG 42
try
{
throw ERR_EVERYTHING_IS_WRONG;
}
catch(int err)
{
//
}
For try-catch, do not use numbers! Use a class derived from a standard exception class. Example:
#include <stdexcept>
class my_error : public std::runtime_error {
public:
explicit my_error(const std::string& what_arg) : std::runtime_error(what_arg) {};
};
Usage (Coliru):
#include <iostream>
int main() {
try {
throw my_error("You can even pass a string here!");
} catch (const my_error& e) {
std::cerr << e.what();
}
}
Or simpler: use std::runtime_error
#include <stdexcept>
#include <iostream>
int main() {
try {
throw std::runtime_error("Error happened");
} catch (const std::runtime_error& e) {
std::cerr << e.what();
}
}
Without standard library:
class my_error {
};
int main() {
try {
throw my_error();
} catch (const my_error& e) {
//TODO handle my_error
}
}
One of the best way is to follow standard for conventions of different errors in C++ codes is Enum
eg:
enum FILE_ERROR{
FILE_NOT_FOUND,
FILE_NO_ACCESS,
FILE_BUSY
};
so in code u can use FILE_NOT_FOUND as error number which is 0 . So this makes easy to understand what error type stands for what
There is no rule, you can do whatever you want as long as you keep a logical way to assign it.
If you choose 3 for bad user input, keep it for only that error or you'll get lost really soon
In C++ it is common to have 1 as success and 0 as error code, unlikely to C, where there are many functions returning 0 as success (strcmp, etc...)
this may be confusing sometimes, especially when interacting with C code, however I find that it helps a lot readability.
if(cplusplus_function()) {...}
is a lot more readable than
if(!c_function()){ ... }
remember also that you have exceptions to leverage in C++, and try to avoid nesting if-s
You don't "throw" any number, you "throw" an exception, an object of a class that derives from std::exception.
Standard exceptions contain text, and do not actually contain an error number. You can however create different classes for different types of exceptions, and have different catch handlers dependent on which exception type was thrown.

why try...catch requires EXACT type thrown

I can do this, no problem:
long lngval = 3L;
int i = lngval;
but if I try this:
try {
throw 3L;
}
catch(int i) {
cout << "caught " << i << endl;
}
I get an unhandled exception.
This seems inconsistent. what is the reason for no type conversion in this case?
In the first case, the compiler can tell exactly what you want to do: convert a long to an int. In the second case, the compiler has to assume that you might have a construct like this:
try {
try {
throw 3L;
}
catch (int i) { /* P */ }
}
catch (long l) { /* Q */ }
The idea is that the compiler can never know whether there might be a catch (long l) lurking outside the current context, so it's never safe to just pick the first possible conversion.
This is also why it's common to use a class hierarchy when throwing exceptions rather than random types like int or long: it makes it easy to add more or less specification to your exception handlers in such a way that the compiler can be sure of your intentions (via the is-a relationship).
catch does not necessarily need the exact type.
It is common and good practice to use exceptions derived from std::exception (found in <stdexcept>). The reason is that you can then catch polymorphically, i.e. you do not need to know the exact type (see also Difference: std::runtime_error vs std::exception()) and that we have a convention to handle this.
Either you use one of the ones provided by the standard (e.g. std::range_error), or if nothing suits your problems [enough], specialize std::exception:
#include <stdexcept>
class moores_law_stopped : public std::exception {
public:
virtual ~moores_law_stopped() throw() {}
virtual const char *what() const throw() {
return "moores law stopped. duck under your table.";
}
};
#include <iostream>
int main () {
try {
throw moores_law_stopped();
} catch (std::exception const &e) {
std::cerr << "oh oh: " << e.what() << std::endl;
}
}
Output:
oh oh: moores law stopped. duck under your table.
The convention is to catch by reference or const reference, so that you get polymorphic behavior without fearing object slicing.
The catch statement catches an object (or a scalar variable in your cases) given its type, so if the type mismatch, it passes to the next catch statement (if there is one) or to the default exception receiver.
In your case, you could have a second catch statement catching long, and maybe somewhere else, so your catch statement won't catch anything.
To catch any exception, just use catch() {} :)
A single tip, better use exception class, or subclass it for you own need :)
You can also throw 3; - no problem.
int and long are different types. It's an advantage of the exception handling that you can tell the exceptions apart from looking at their type (one central try block can handle exceptions of various kinds from various places / a try block can handle just some kinds of exceptions, letting others propagate).
Also, it is recommended to throw one of the standard exceptions or derive a class from one of those. Then you could just catch (const std::exception&) if you just want to handle the exception and don't care about the particular type.
You can catch multiple types in one try-catch block. In order for the compiler to know which catch block to throw to, it must be able to match the exact type. Or it can have a default catch block -- catch (...) {}, but you won't be able to get at the value thrown in that case.