How to organize dozens of similar try-catch blocks? - c++

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.

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."));
}

Inherit from std::exception without changing users code

Currently within our API we have our own exception-type MyException which does not (neither directly nor indirectly) inherit from std::exception or any other type:
class MyException {
public:
MyException(std::string const& message);
std::string const& GetErrorMessage() const;
private:
//...stuff, e.g. like the error-message.
};
To our customers (and our own developers ) this leads the burden of always adding at least two catch-handler to a try-block:
try {
SomeLibraryFunction();
}
catch (MyException const& e) { std::cerr << e.GetErrorMessage(); }
catch (std::exception const& e) { std::cerr << e.what(); }
To reduce the number of catch-handler I would like to add inheritance from std::exception. But the problem with that is that it will "break" existing code. Namely the compiler will choose a different catch-handler than it did before:
try {
SomeOtherLibraryFunction();
}
catch(std::exception const& e) { std::cerr << "STD-EX"; }
catch(MyException const& e)
{
std::cerr << "LIBRARY-EX";
ExecuteMandatoryCodeWhenMyExceptionGetsThrown(e);
}
As soon as MyException inherits from std::exception the second catch-handler will never be reached. The reason for that is stated here:
When an exception of type E is thrown by any statement in compound-statement, it is matched against the types of the formal parameters T of each catch-clause in handler-seq, in the order in which the catch clauses are listed.
Is there a way that the compiler will take the catch-clause that is the best match instead of taking the first match? Or any other way to achieve the inheritance from std::exceptionwithout changing which catch-handler will be called?
The safest way is to change the exception type to a new type in this case, e.g. MyExceptionV2, educate people that it is much better, and that MyException is going to be deprecated eventually. Then give them time to upgrade their catch blocks to use your new type and remove the extra catch blocks. Then deprecate it in the next version, then remove MyException in the later version.

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.

C++ - Where to throw exception?

I have some kind of an ideological question, so:
Suppose I have some templated function
template <typename Stream>
void Foo(Stream& stream, Object& object) { ... }
which does something with this object and the stream (for example, serializes that object to the stream or something like that).
Let's say I also add some plain wrappers like (and let's say the number of these wrappers equals 2 or 3):
void FooToFile(const std::string& filename, Object& object)
{
std::ifstream stream(filename.c_str());
Foo(stream, object);
}
So, my question is:
Where in this case (ideologically) should I throw the exception if my stream is bad? Should I do this in each wrapper or just move that check to my Foo, so that it's body would look like
if (!foo.good()) throw (something);
// Perform ordinary actions
I understand that this may be not the most important part of coding and these solutions are actually equal, but I just wan't to know "the proper" way to implement this.
Thank you.
In this case it's better to throw it in the lower-level Foo function so that you don't have to copy the validation and exception throwing code in all of your wrappers. In general using exceptions correctly can make your code a lot cleaner by removing a lot of data validation checking that you might otherwise do redundantly at multiple levels in the call stack.
I would prefer not to delay notifying an error. If you know after you have created the stream, that it is no good, why call a method that works on it? I know that to reduce code-redundancy you plan to move it further down. But the downside of that approach is a less-specific error message. So this depends to some extent on the source-code context. If you could get away with a generic error message at the lower-function level you can add the code there, this will surely ease maintanence of the code especially when there are new developers on the team. If you need a specific error message better handle it at the point of failure itself.
To avoid code redundancy call a common function that makes this exception/error for you. Do not copy/paste the code in every wrapper.
The sooner you catch the exceptiont the better. The more specific the exception is - the better. Don't be scared of including most of your code into a try catch blocks, apart fromt he declaration.
For example:
int count = 0;
bool isTrue = false;
MyCustomerObject someObject = null;
try
{
// Initialise count, isTrue, someObject. Process.
}
catch(SpecificException e)
{
// Handle and throw up the stack. You don't want to lose the exception.
}
I like to use helper functions for this:
struct StreamException : std::runtime_error
{
StreamException(const std::string& s) : std::runtime_error(s) { }
virtual ~StreamException() throw() { }
};
void EnsureStreamIsGood(const std::ios& s)
{
if (!s.good()) { throw StreamException(); }
}
void EnsureStreamNotFail(const std::ios& s)
{
if (s.fail()) { throw StreamException(); }
}
I test them immediately before and after performing stream operations if I don't expect a failure.
Traditionally in C++, stream operations don't throw exceptions. This is partly for historic reasons, and partly because streaming failures are expected errors. The way C++ standard stream classes deal with this is to set a flag on a stream to indicate an error has occurred, which user code can check. Not using exceptions makes resumption (which is often required for streaming ops) easier than if exceptions were thrown.

Code reuse in exception handling

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).