Consider the following resource managing class
class FooResouce
{
public:
explicit FooResouce(T arg_to_construct_with)
{
m_foo = create_foo_resouce(arg_to_construct_with);
if(m_foo == nullptr)
{throw SomeException(get_foo_resource_error(), arg_to_construct_with);}
}
// Dtor and move operations
// Other FooResource interaction methods
private:
foo_resource_t* m_foo;
};
Now, when we decide to catch the exception and format an error message, it's easy to know what caused the exception at the fundamental level, but we have no information about where the exception was triggered in the upper level. Here upper level refers the function that tried to create a FooResource, or any function above that stack frame. How would you add context to the error in case that is needed:
Pass some optional context information as an extra argument to the Ctor, which can then be stored in the exception
At callsite use a pushContext function. This function will store the context using thread-local storage.
Catch and rethrow. I think the code would be ugly in this case.
Although this solution conflicts with your third requirement 3: No Catch and rethrow, I propose an solution with std::nested_exception and macros because this seems to provide a reasonable solution for the current problem at least to me.
I hope this too long answer can help you.
1. An Error Handling with std::nested_exception
First, we can recursively nest exceptions using std::nested_exception.
Roughly speaking, We can add exceptions of arbitrary types to this class by calling std::throw_with_nested.
These enables us to carry all information of thrown exceptions with a rather simple code, just throwing each exception by std::throw_with_nested in each ellipsis catch handler catch(…){ } in the upper level.
For instance, following function h throws a std::nested_exception which aggregates the user-defined exception SomeException and std::runtime_error:
struct SomeException : public std::logic_error {
SomeException(const std::string& message) : std::logic_error(message) {}
};
[[noreturn]] void f(){
std::throw_with_nested(SomeException("error."));
}
[[noreturn]] void g()
{
try {
f();
}
catch (...) {
std::throw_with_nested(std::runtime_error("Error of f."));
}
};
[[noreturn]] void h()
{
try {
g();
}
catch (...) {
std::throw_with_nested(std::runtime_error("Error of g."));
}
}
Locating Exceptions (Fundamental Level)
Replacing all of these std::throw_with_nested by the following function throw_with_nested_wrapper through the macro THROW_WITH_NESTED, we can make records of the file names and the line numbers where exceptions occurred.
As is well known, __FILE__ and __LINE__ are pre-defined by C++ standard.
So the macro THROW_WITH_NESTED has a key role to add these location information:
// "..." are arguments of the ctor of ETYPE
// and the first one must be a string literal.
#define THROW_WITH_NESTED(ETYPE, ...) \
throw_with_nested_wrapper<ETYPE>(__FILE__, __LINE__, __VA_ARGS__);
template<typename E, typename ...Args>
[[noreturn]]
void throw_with_nested_wrapper(
char const* fileName,
std::size_t line,
const std::string& message,
Args&& ...args)
{
auto info = std::string(fileName)
+ ", l." + std::to_string(line) + ", "
+ message;
std::throw_with_nested(E(info, std::forward<decltype(args)>(args)...));
};
Locating Exceptions (Upper Level)
If we have to pick up information about where the exception was triggered in the upper level, the following macro HOOK reusing the above macro THROW_WITH_NESTED would work for us:
#define HOOK(OPERATION) \
[&]() \
{ \
try{ \
return OPERATION; \
} \
catch(...){ \
auto info = std::string(#OPERATION) + ", upper level."; \
THROW_WITH_NESTED(std::runtime_error, info); \
} \
}()
Finally, first three functions f, g and h are rewritten and simplified as follows:
[[noreturn]] void f(){
THROW_WITH_NESTED(SomeException, "SomeException, fundamental level.");
}
void g(){
HOOK(f());
};
void h(){
HOOK(g());
}
Extracting Error Information
Extracting all explanatory information of nested exceptions is a simple task.
Passing the caught exception at the most outer try-catch block into the following function output_exceptions_impl, we can do it.
Each nested exception can be recursively thrown by std::nested_exception::rethrow_nested.
Since this member function calls std::terminate when there is no stored exception, we should apply dynamic_cast to avoid it as pointed out in this post:
template<typename E>
std::enable_if_t<std::is_polymorphic<E>::value>
rethrow_if_nested_ptr(const E& exception)
{
const auto *p =
dynamic_cast<const std::nested_exception*>(std::addressof(exception));
if (p && p->nested_ptr()){
p->rethrow_nested();
}
}
void output_exceptions_impl(
const std::exception& exception,
std::ostream& stream,
bool isFirstCall = false)
{
try
{
if (isFirstCall) { throw; }
stream << exception.what() << std::endl;
rethrow_if_nested_ptr(exception);
}
catch (const std::runtime_error& e) {
stream << "Runtime error: ";
output_exceptions_impl(e, stream);
}
/* ...add further catch-sections here... */
catch(...){
stream << "Unknown Error.";
}
}
BTW, explicit try-catch blocks at the most outer places are rather verbose and thus I usually use the following macro proposed in this post:
#define CATCH_BEGIN try{
#define CATCH_END(OSTREAM) } catch(...) { output_exceptions(OSTREAM); }
void output_exceptions(std::ostream& stream)
{
try {
throw;
}
catch (const std::exception& e) {
output_exceptions_impl(e, stream, true);
}
catch (...) {
stream << "Error: Non-STL exceptions." << std::endl;
}
}
Then all exceptions thrown from h can be traced and printed by the following code.
Inserting the macros THROW_WITH_NESTED, HOOK, CATCH_BEGIN and CATCH_END at the right lines of our code, we can locate exceptions in each thread:
CATCH_BEGIN // most outer try-catch block in each thread
...
HOOK(h());
...
CATCH_END(std::cout)
Then we get the following output where file names and line numbers are just an examples.
All the available information is recorded:
DEMO with 2 threads
Runtime error: prog.cc, l.119, h(), upper level.
Runtime error: prog.cc, l.113, g(), upper level.
Runtime error: prog.cc, l.109, f(), upper level.
Logic error: prog.cc, l.105, SomeException, fundamental level.
2. In case of FooResouce
First requirement is
Pass some optional context information as an extra argument to the Ctor, which can then be stored in the exception
Let us define the following special exception class SomeException which contains some optional context information and the member function getContext to get it:
class SomeException : public std::runtime_error
{
std::string mContext;
public:
SomeException(
const std::string& message,
const std::string& context)
: std::runtime_error(message), mContext(context)
{}
const std::string& getContext() const noexcept{
return mContext;
}
};
Adding a new argument context to FooResouce::FooResouce and replacing throw by THROW_WITH_NESTED, we can pass the first requirement within the above error handling framework:
class FooResouce
{
public:
FooResouce(
T arg_to_construct_with,
const std::string& context)
{
m_foo = create_foo_resouce(arg_to_construct_with);
if(!m_foo){
THROW_WITH_NESTED(SomeException, "Ctor failed.", context);
}
...
}
...
};
Next,
but we have no information about where the exception was triggered in the upper level. Here upper level refers the function that tried to create a FooResource,
Creating each FooResource with HOOK, we can get information about where the ctor was failed in the upper level.
The caller side would be as follows.
In this manner, all error information including messages, contexts and their locations would be clarified in each thread.
CATCH_BEGIN // most outer try-catch block in each thread
...
auto resource = HOOK(FooResouce(T(), "context"));
...
CATCH_END(std::cout)
Finally,
At callsite use a pushContext function. This function will store the context using thread-local storage.
Although I don't know the detail of this requirement, but since we can call SomeException::getContext in output_exceptions_impl as follows and get all contexts from every thrown SomethingExceptions, I think we can also store them like this:
DEMO(my proposal)
void output_exceptions_impl(
const std::exception& exception,
std::ostream& stream,
bool isFirstCall = false)
{
...
catch (const SomeException& e) { // This section is added.
stream
<< "SomeException error: context:"
<< e.getContext() << ", "; // or pushContext?
output_exceptions_impl(e, stream);
}
...
}
Related
I have some code that looks like this:
const SomeType & elt = x.find();
try {
// ... do something with elt ...
} catch (...) {
// handle processing exception
}
And it works, but due to changing circumstances, it's now possible for that find() method to throw a "not found" exception, which I need to catch.
What I'd like to write would be
try {
const SomeType & elt = x.find();
} catch (...) {
// handle "not found" exception
return;
}
try {
// ... do something with elt ...
} catch (...) {
// handle processing exception
}
But of course this doesn't work, because elt is no longer in scope by the time its processing block is reached. I can't rearrange this to
const SomeType & elt;
try {
elt = x.find();
} catch (...) {
// handle "not found" exception
return;
}
because of course reference types in C++ aren't allowed to be uninitialized. So I'm left with the options of temporarily setting elt to be a reference to a dummy object of type SomeType, which I'd rather not do, or nesting the try/catch blocks, like this:
try {
const SomeType & elt = x.find();
try {
// ... do something with elt ...
} catch (...) {
// handle processing exception
}
} catch (...) {
// handle "not found" exception
}
I don't like this, either: the nesting is confusing, and I don't like the way the "not found" exception handler is hiding down there at the end.
Can anyone think of a better way to arrange this? (In C, of course, we'd just have the find function return a null pointer in the not-found case, and handle it that way, but I like to try not to be an old C programmer when I'm writing C++, and anyway x.find() is already set up to return a reference, not a pointer.)
If exceptions are different, you might use the same try block:
try {
const SomeType& elt = x.find();
// ... do something with elt ...
} catch (const NotFoundException&) {
// handle "not found" exception
} catch (...) {
// handle processing exception
}
else rebinding reference is not allowed, but might be simulated by pointer or std::reference_wrapper in general,
And optional reference (not allowed neither in std, but boost allow it) might be simulated by pointer or std::optional<std::reference_wrapper<T>>.
So:
const SomeType* eltPtr = nullptr;
try {
eltPtr = &x.find();
} catch (const NotFoundException&) {
// handle "not found" exception
return;
}
const SomeType& elt = *eltPtr;
try {
// ... do something with elt ...
} catch (...) {
// handle processing exception
}
Split into another function:
void func1()
{
try {
const SomeType & elt = x.find();
func2(elt);
} catch (...) {
// handle "not found" exception
}
}
void funct2(const SomeType & elt)
{
try {
// ... do something with elt ...
} catch (...) {
// handle processing exception
}
}
Though in general I find your interface slightly disturbing to require all these try/catch blocks in the first place. Unfortunately it is hard to offer advice on how to improve the general style with such little information.
It will not be to everyone's taste (the behaviour is defined by the way), but you could use
#include <functional>
std::reference_wrapper<const SomeType> elt = elt;
try {
elt = x.find();
} catch (...) {
// handle "not found" exception
return;
}
Arguably the setting of elt to itself is an abuse of std::reference_wrapper, which has its default and move constructors deleted by design: I'm circumventing that.
Essentially std::refernce_wrapper is a pointer under the hood but you can rebind it, which is essentially what you want to do here.
You probably know situations like this where you just want to assign to a (const) variable with an expression which might fail (throw) (e.g.container.at()) which forces you to write boiler plate code:
void foo(const string &key) {
auto it = data_store.find(key);
if (it == data_store.end()) {
return;
}
const auto & element = it->second;
...
go on with `element`...
...
}
In Python you could write code like this:
def foo(name):
try:
element = data_store[key]
except KeyError:
return
..
go on with `element`
..
.. with is less noisy because you don't introduce that useless extra it just for checking existence.
If C++'s try would not introduce a variable scope you could just use at():
void foo(const string &key) {
try {
const auto & element = data_store.at(key);
} catch (const out_of_range &) {
return;
}
...
go on with `element`...
...
}
What's the way to go here if you don't want to abandon constness and keep your code clean?
If lambdas only could have a try/catch body you could write
void foo(const string &key) {
const auto & element = [&] () -> T try {
return data_store.at(key);
} catch () {
return;
} ();
...
go on with `element`...
...
}
Some answers to similar questions suggest try/catch blocks around all the code:
void foo(const string &key) {
try {
const auto & element = data_store.at(key);
...
go on with `element`...
...
} catch (const out_of_range &) {
return;
} catch (some other exception) {
...
} catch (some other exception) {
...
}
}
But I don't like this because of three reasons:
there's no visual correlation between at() and it's catch block
there might be code that also need you to handle out_of_range
you have to write nested code
Which (nice, short and clean) alternatives do you know?
There are three good options on this thread, there's not really any other option.
Those cases assume we are initializing an object; for initializing a reference as you are, apply the techniques to std::reference_wrapper, or a pointer.
BTW I would not discount your first code sample so quickly. It's simpler than all the other options, and it is a common recommendation in C++ to only use exceptions for exceptional conditions -- things you do not expect to be a normal part of the function's contract. It's not idiomatic to use them as a shortcut.
In other words, if the function design is to do nothing if the lookup fails, then throw-catching is an unnecessary complication to the function. You've just written an even uglier version of C-style error handling.
The whole point of the at() accessor is that your function can be kept simple by not catching -- the exception can be left to propagate up to a more general error handler.
C++ classes provide RAII idiom. Therefore you don't have to care about exceptions:
void function()
{
// The memory will be freed automatically on function exit
std::vector<int> vector(1000);
// Do some work
}
But if you have (for some reasons) to use some pure C API, you have either to create C++ wrappers around it or to use try/catch blocks
void function()
{
int *arr = (int*)malloc(1000*sizeof(int));
if (!arr) { throw "cannot malloc"; }
try
{
// Do some work
}
catch (...)
{
free(arr); // Free memory in case of exception
throw; // Rethrow the exception
}
// Free memory in case of success
free(arr);
}
Even if you use C++ classes with RAII idiom, sometimes you have to write a code with strong exception-safety guaranty:
void function(std::vector<const char*> &vector)
{
vector.push_back("hello");
try
{
// Do some work
vector.push_back("world");
try
{
// Do other work
}
catch (...)
{
vector.pop_back(); // Undo vector.push_back("world")
throw; // Rethrow the exception
}
}
catch (...)
{
vector.pop_back(); // Undo vector.push_back("hello");
throw; // Rethrow the exception
}
}
But these constructions are quite bulky.
Is there any way to force to run some cleanup code at function exit? Something similar to atexit, but in a function scope...
Is there any way to run some rollback code in case of exception without using nested try/catch blocks?
I would like to have some operators or functions that would work like this:
void function(std::vector<const char*> &vector)
{
int *arr = malloc(1000*sizeof(int));
onexit { free(arr); }
vector.push_back("hello");
onexception { vector.pop_back(); }
// Do some work
vector.push_back("world");
onexception { vector.pop_back(); }
// Do other work
}
If it is possible to create such functions, are there any reasons to avoid using them? Are there such constructs in other programming languages?
I have created macros that implement this functionality. They generate a local variable that runs a cleanup code in the destructor using C++11 lambda functions. The std::uncaught_exception function is used to check if there is any exception currently thrown. Creating the variable itself shouldn't throw any exceptions because a lambda with all variables captured by reference is used to create the variable (such lambdas do not throw exceptions in copy/move constructors).
#include <exception>
// An object of the class below will run an arbitrary code in its destructor
template <bool always, typename TCallable>
class OnBlockExit
{
public:
TCallable m_on_exit_handler;
~OnBlockExit()
{
if (always || std::uncaught_exception())
{ m_on_exit_handler(); }
}
};
// It is not possible to instantiate an object of the 'OnBlockExit' class
// without using the function below: https://stackoverflow.com/a/32280985/5447906.
// Creating of an object of the 'OnBlockExit' class shouldn't throw any exception,
// if lambda with all variables captured by reference is used as the parameter.
template <bool always, typename TCallable>
OnBlockExit<always, TCallable> MakeOnBlockExit(TCallable &&on_exit_handler)
{
return { std::forward<TCallable>(on_exit_handler) };
}
// COMBINE is needed for generating an unique variable
// (the name of the variable contains the line number:
// https://stackoverflow.com/a/10379844/544790)
#define COMBINE1(X,Y) X##Y
#define COMBINE(X,Y) COMBINE1(X,Y)
// ON_BLOCK_EXIT generates a variable with the name
// in the format on_block_exit##__LINE__
#define ON_BLOCK_EXIT(always, code) \
auto COMBINE(on_block_exit,__LINE__) = MakeOnBlockExit<always>([&]()code)
// Below are target macros that execute the 'code' on the function exit.
// ON_FINALLY will allways execute the code on the function exit,
// ON_EXCEPTION will execute it only in the case of exception.
#define ON_EXCEPTION(code) ON_BLOCK_EXIT(false, code)
#define ON_FINALLY(code) ON_BLOCK_EXIT(true , code)
Here is an example how to use these macros:
void function(std::vector<const char*> &vector)
{
int *arr1 = (int*)malloc(800*sizeof(int));
if (!arr1) { throw "cannot malloc arr1"; }
ON_FINALLY({ free(arr1); });
int *arr2 = (int*)malloc(900*sizeof(int));
if (!arr2) { throw "cannot malloc arr2"; }
ON_FINALLY({ free(arr2); });
vector.push_back("good");
ON_EXCEPTION({ vector.pop_back(); });
auto file = fopen("file.txt", "rb");
if (!file) { throw "cannot open file.txt"; }
ON_FINALLY({ fclose(file); });
vector.push_back("bye");
ON_EXCEPTION({ vector.pop_back(); });
int *arr3 = (int*)malloc(1000*sizeof(int));
if (!arr3) { throw "cannot malloc arr3"; }
ON_FINALLY({ free(arr3); });
arr1[1] = 1;
arr2[2] = 2;
arr3[3] = 3;
}
All cleanup code is executed in reverse order (in the order opposite to the order of the ON_FINALLY/ON_EXCEPTION macros appearance in the function). The cleanup code is executed only if control passes beyond the corresponding ON_FINALLY/ON_EXCEPTION macro.
Check the following link to see the output of the demo program execution: http://coliru.stacked-crooked.com/a/d6defaed0949dcc8
C++ has destructors which is what you need. An object that does whatever you need done at scope exit in its destructor that you then create an instance of on the stack in the scope where you need the work done, will get destroyed when the scope is left and then do the work at that time.
ScopeGuard is the right choice for you. It basically calls the function you specify at destructor.
So your code can be:
void your_function() {
scope_guard guard = [&vector]() {
vector.pop_back();
};
// your code
guard.dismiss(); // success
}
I have the following pattern:
task<Param1^> MyClass::MethodA(String^ s)
{
return create_task([this, s]
{
....
IAsyncOperation<Param1^>^ result = SystemMethod1ReturningParam1(...);
return result;
});
}
IAsyncOperation<Param2^>^ MyClass::MethodB(String^ s)
{
return create_async([this, s]
{
return MethodA(s).then([this](task<Param1^> t)
{
Param1^ p1 = t.get();
....
Param2^ result = SystemMethod2ReturningParam2(p1);
return result ;
});
});
}
I call public MethodB which calls private MethodA. Param1 is standard enum that I cannot change. MethodA create_task my need to return error condition. I cannot return null. MethodB also needs return error condition.
What's the best way to return errors from both methods?
SystemMethod1ReturningParam1 and SystemMethod2ReturningParam2 which are framework system methods can throw exceptions. Where do I catch them?
If you are worried about exceptions, you should always use task-based continuations and wrap the call to task.get() in a try/catch.
Note that the code below (and other C++ code) throws std::exception, but if you are interfacing with WinRT components and you want the exception to propagate, you must re-throw as a Platform::Exception value.
concurrency::task<int> throw_async()
{
return concurrency::create_task([]
{
throw std::exception("oops");
return -1;
});
}
void test_value()
{
// This will crash inside PPL runtime due to unobserved exception
throw_async().then([](int x)
{
OutputDebugString(L"You'll never see this\r\n");
});
}
void test_task()
{
// This will handle the exception correctly
throw_async().then([](concurrency::task<int>& t)
{
OutputDebugString(L"You'll see this\r\n");
try
{
auto val = t.get();
OutputDebugString(L"You'll never see this\r\n");
}
catch (std::exception& ex)
{
auto error = ex.what(); // "oops"
// Need to re-throw if this crosses the WinRT ABI boundary.
// Conversion of 'error' to Platform::String^ omitted for brevity
throw ref new Platform::FailureException(/* error */);
}
});
}
The scenario:
We have an API that has a generic error handling interface. It is a C API, so it tells us that after every API function called, we need to execute some boilerplate like this:
if (APIerrorHappened()) {
APIHandle h;
while(h = APIgetNextErrorContext(...)) {
cerr << APIgetText(h) << endl;
}
}
You obviously hate repeating yourself, so you want to encapsulate this handling in a macro that allows you to write code like this:
...
// this API call returns something
APItype foo = MYMACRO(APIsomeFunction1(...));
// this one doesn't
MYMACRO(APIsomeFunction2(...));
// neither does this (glCompileShader)
MYMACRO(APIsomeFunction3(...));
...
You can also think of this in terms of aspect-oriented programming - imagine that the macro adds logging, sends info to remote monitor, whatever... The point is that it is supposed to encapsulate an expression, do whatever around it, and return whatever type the expression returns - and of course the expression may not return anything.
Which means you can't just do
#define MYMACRO(x) { auto x = expr(); ... }
...because in some cases, the expression doesn't return anything!
So... How would you do that?
Please don't suggest encapsulating the complete statement inside the macro...
#define MYMACRO(x) \
{ \
/* ... stuff ... */ \
x; \
// ... stuff
}
...since this would never work for stuff like:
if (foo() || APIfunctionReturningBool(...) || bar()) {
...
APIfunction1();
...
} else if (APIOtherfunctionReturningBool() || baz()) {
...
APIfunction2();
...
}
...you engulf all the if statement? Its actions include other API calls, so... macro within macro? Debugging just became hell.
My own attempt is below, using lambdas and std::function - but it is arguably, ugly...
I could not pass a lambda of the expression directly to a template that takes std::function (to specialize based on the lambda's return type), so the code turned out rather nasty.
Can you think of a better way?
void commonCode(const char *file, size_t lineno) {
// ... error handling boilerplate
// ... that reports file and lineno of error
}
template <class T>
auto MyAPIError(std::function<T()>&& t, const char *file, size_t lineno) -> decltype(t()) {
auto ret = t();
commonCode(file,lineno);
return ret;
}
template<>
void MyAPIError(std::function<void(void)>&& t, const char *file, size_t lineno) {
t();
commonCode(file,lineno);
}
template <class T>
auto helper (T&& t) -> std::function<decltype(t())()>
{
std::function<decltype(t())()> tmp = t;
return tmp;
}
#define APIERROR( expr ) \
return MyAPIError( helper( [&]() { return expr; } ), __FILE__, __LINE__);
UPDATE, an addendum to KennyTM's excellent solution
I placed the actual OpenGL code that triggered this question here. As you can see, the error checking code did more than just print - it also threw an exception that the user code could then handle. I am adding this addendum to note that with KennyTM's solution, you end up throwing this exception from a destructor, and that this is OK (read on):
struct ErrorChecker {
const char *file;
size_t lineno;
~ErrorChecker() {
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
while (err != GL_NO_ERROR) {
std::cerr <<
"glError: " << (char *)gluErrorString(err) <<
" (" << file << ":" << lineno << ")" << std::endl;
err = glGetError();
}
throw "Failure in GLSL...";
}
}
};
The reason it is OK to throw from this destructor, is explained in the C++ FAQ:
The C++ rule is that you must never throw an exception from a destructor that is being called during the "stack unwinding" process of another exception... you can say never throw an exception from a destructor while processing another exception.
In our case, we want the user code (that calls the special macro) to handle the exception; so we need to know for certain that our "throw" in the ErrorChecker's destructor is the first one - i.e. that the actual C API called can never throw. This is easily accomplished with this form:
#define GLERROR(...) \
([&]() -> decltype(__VA_ARGS__) \
{ \
ErrorChecker _api_checker {__FILE__, __LINE__}; \
(void) _api_checker; \
try { \
return __VA_ARGS__; \
} catch(...) {} \
} ())
This form of the macro guarantees that the actual C API (called via VA_ARGS) will never throw - and therefore, the "throw" in ErrorChecker's destructor will always be the first one doing it.
So this solution covers all angles of my original question - many thanks to Alexander Turner for providing it.
Put the logging code to a destructor of some class — assuming the logger won't throw — and then create an instance of that class in the macro. Abusing the comma operator, we have:
struct Logger
{
const char* file;
int lineno;
~Logger()
{
// The APIerrorHappened stuff.
}
};
#define APIERROR(...) (Logger{__FILE__, __LINE__}, (__VA_ARGS__))
Demo: http://ideone.com/CiLGR