D-style scope guards?

Hi, I have used the good old scopeguard in the past and recently done some experiments with the Boost.ScopeExit library. Still I feel that the clean scope statements in D is missing. It will not be possible to do an equally clean solution without having the same features in the language itself, but I could reach as far as this example that reuses the ScopeExit library: void foo() { GUARDED_SCOPE_BEGIN GUARDED_SCOPE_EXIT() { cout << "Returning from foo()" << endl; } GUARDED_SCOPE_EXIT_END GUARDED_SCOPE_SUCCESS() { cout << "foo(): No Errors occurred!" << endl; } GUARDED_SCOPE_SUCCESS_END GUARDED_SCOPE_FAILURE() { cout << "foo(): Exception caught!" << endl; } GUARDED_SCOPE_FAILURE_END GUARDED_SCOPE_END } The GUARDED_SCOPE_BEGIN macro declares one boolean guard to handle return from several levels of nested scopes and one boolean to guard the current scope from exceptions (will be shadowed in nested scopes). GUARDED_SCOPE_END will set the exception_thrown guard to false before that variable is used by the GUARDED_SCOPE_*() destructors. The latter is actually reused ScopeExit code with an added wrapper with a single if-statement. GUARDED_SCOPE_EXIT() will allways run on scope exit. GUARDED_SCOPE_SUCCESS() will only run if the function is exited with wrapper for return keyword (GUARDED_SCOPE_RETURN). The wrapper must be used since it updates the hidden guard variables. Using plain "return" will behave as if exception was thrown. GUARDED_SCOPE_FAILURE() will run when exception is thrown. There is also a separate GUARDED_SCOPE_NESTED_BEGIN that is supposed to be used for all nested scopes. A reference is kept to the return_called variable in the top-level-scope (variable declared by GUARDED_SCOPE_BEGIN). The biggest issue here is that any extra closing curly bracket inserted between GUARDED_SCOPE_*-definitions and GUARDED_SCOPE_END will cause destructors to run before update of guard variable. Could happen if someone thinks it "looks better" without understanding how stuff works. That kind of error will behave as if exception was thrown. Is this something to investigate further? Messy or potentially useful? Suggestions for improvements? I've appended the contents of my small test program at the end of this email. Can be tested by inserting GUARDED_SCOPE_RETURN() and "throw exception();". Regards, /Martin ----------- #include <iostream> #include <exception> #include <boost/scope_exit.hpp> using namespace std; #define GUARDED_SCOPE_BEGIN bool return_called = false; { bool& return_called_ref = return_called; bool exception_thrown = true; #define GUARDED_SCOPE_NESTED_BEGIN { bool& return_called_ref = return_called; bool exception_thrown = true; #define GUARDED_SCOPE_END exception_thrown = false; (void) return_called_ref; } #define GUARDED_SCOPE_RETURN(rc) { return_called_ref = true; return rc; } #define GUARDED_SCOPE_EXIT(Seq) BOOST_SCOPE_EXIT(Seq) #define GUARDED_SCOPE_EXIT_END BOOST_SCOPE_EXIT_END #define GUARDED_SCOPE_SUCCESS(Seq) BOOST_SCOPE_EXIT( (&return_called_ref) (&exception_thrown) Seq) { if(return_called_ref || !exception_thrown) #define GUARDED_SCOPE_SUCCESS_END } BOOST_SCOPE_EXIT_END #define GUARDED_SCOPE_FAILURE(Seq) BOOST_SCOPE_EXIT( (&return_called_ref) (&exception_thrown) Seq) { if(!return_called_ref && exception_thrown) #define GUARDED_SCOPE_FAILURE_END } BOOST_SCOPE_EXIT_END void foo() { GUARDED_SCOPE_BEGIN GUARDED_SCOPE_EXIT() { cout << "Returning from foo()" << endl; } GUARDED_SCOPE_EXIT_END GUARDED_SCOPE_SUCCESS() { cout << "foo(): No Errors occurred!" << endl; } GUARDED_SCOPE_SUCCESS_END GUARDED_SCOPE_FAILURE() { cout << "foo(): Exception caught!" << endl; } GUARDED_SCOPE_FAILURE_END do { GUARDED_SCOPE_NESTED_BEGIN GUARDED_SCOPE_FAILURE() { cout << "Inner scope: Exception caught!" << endl; } GUARDED_SCOPE_FAILURE_END GUARDED_SCOPE_SUCCESS() { cout << "Inner scope: No Errors occurred!" << endl; } GUARDED_SCOPE_SUCCESS_END GUARDED_SCOPE_END } while(0); GUARDED_SCOPE_END } int main() { try { foo(); } catch(exception& e) { cout << "main(): Caught exception: " << e.what() << endl; return -1; } cout << "main(): No Errors occurred!" << endl; return 0; }

Why don't you use std::uncaught_exception() instead of exception_thrown? Also in my opinion this is a cleaner solution: void foo() { BOOST_SCOPE_EXIT(empty capture list not supported yet) cout << "Returning from foo()" << endl; if(!std::uncaught_exception()) cout << "foo(): No Errors occurred!" << endl; else cout << "foo(): Exception caught!" << endl; BOOST_SCOPE_EXIT_END // ... } Anyway in real code using a commit variable directly reflects the intent better. Perhaps if I'm wrong, please give a real-world example when your scope guards are more appropriate. On Fri, Sep 17, 2010 at 09:06, Martin Christiansson < martin.christiansson@gmail.com> wrote:
Hi,
I have used the good old scopeguard in the past and recently done some experiments with the Boost.ScopeExit library. Still I feel that the clean scope statements in D is missing.
It will not be possible to do an equally clean solution without having the same features in the language itself, but I could reach as far as this example that reuses the ScopeExit library:
void foo() { GUARDED_SCOPE_BEGIN
GUARDED_SCOPE_EXIT() { cout << "Returning from foo()" << endl; } GUARDED_SCOPE_EXIT_END
GUARDED_SCOPE_SUCCESS() { cout << "foo(): No Errors occurred!" << endl; } GUARDED_SCOPE_SUCCESS_END
GUARDED_SCOPE_FAILURE() { cout << "foo(): Exception caught!" << endl; } GUARDED_SCOPE_FAILURE_END
GUARDED_SCOPE_END }
The GUARDED_SCOPE_BEGIN macro declares one boolean guard to handle return from several levels of nested scopes and one boolean to guard the current scope from exceptions (will be shadowed in nested scopes). GUARDED_SCOPE_END will set the exception_thrown guard to false before that variable is used by the GUARDED_SCOPE_*() destructors. The latter is actually reused ScopeExit code with an added wrapper with a single if-statement. GUARDED_SCOPE_EXIT() will allways run on scope exit. GUARDED_SCOPE_SUCCESS() will only run if the function is exited with wrapper for return keyword (GUARDED_SCOPE_RETURN). The wrapper must be used since it updates the hidden guard variables. Using plain "return" will behave as if exception was thrown. GUARDED_SCOPE_FAILURE() will run when exception is thrown.
There is also a separate GUARDED_SCOPE_NESTED_BEGIN that is supposed to be used for all nested scopes. A reference is kept to the return_called variable in the top-level-scope (variable declared by GUARDED_SCOPE_BEGIN).
The biggest issue here is that any extra closing curly bracket inserted between GUARDED_SCOPE_*-definitions and GUARDED_SCOPE_END will cause destructors to run before update of guard variable. Could happen if someone thinks it "looks better" without understanding how stuff works. That kind of error will behave as if exception was thrown.
Is this something to investigate further? Messy or potentially useful? Suggestions for improvements? I've appended the contents of my small test program at the end of this email. Can be tested by inserting GUARDED_SCOPE_RETURN() and "throw exception();".
Regards, /Martin
-----------
#include <iostream> #include <exception>
#include <boost/scope_exit.hpp>
using namespace std;
#define GUARDED_SCOPE_BEGIN bool return_called = false; { bool& return_called_ref = return_called; bool exception_thrown = true; #define GUARDED_SCOPE_NESTED_BEGIN { bool& return_called_ref = return_called; bool exception_thrown = true; #define GUARDED_SCOPE_END exception_thrown = false; (void) return_called_ref; }
#define GUARDED_SCOPE_RETURN(rc) { return_called_ref = true; return rc; }
#define GUARDED_SCOPE_EXIT(Seq) BOOST_SCOPE_EXIT(Seq) #define GUARDED_SCOPE_EXIT_END BOOST_SCOPE_EXIT_END
#define GUARDED_SCOPE_SUCCESS(Seq) BOOST_SCOPE_EXIT( (&return_called_ref) (&exception_thrown) Seq) { if(return_called_ref || !exception_thrown) #define GUARDED_SCOPE_SUCCESS_END } BOOST_SCOPE_EXIT_END
#define GUARDED_SCOPE_FAILURE(Seq) BOOST_SCOPE_EXIT( (&return_called_ref) (&exception_thrown) Seq) { if(!return_called_ref && exception_thrown) #define GUARDED_SCOPE_FAILURE_END } BOOST_SCOPE_EXIT_END
void foo() { GUARDED_SCOPE_BEGIN
GUARDED_SCOPE_EXIT() { cout << "Returning from foo()" << endl; } GUARDED_SCOPE_EXIT_END
GUARDED_SCOPE_SUCCESS() { cout << "foo(): No Errors occurred!" << endl; } GUARDED_SCOPE_SUCCESS_END
GUARDED_SCOPE_FAILURE() { cout << "foo(): Exception caught!" << endl; } GUARDED_SCOPE_FAILURE_END
do { GUARDED_SCOPE_NESTED_BEGIN
GUARDED_SCOPE_FAILURE() { cout << "Inner scope: Exception caught!" << endl; } GUARDED_SCOPE_FAILURE_END
GUARDED_SCOPE_SUCCESS() { cout << "Inner scope: No Errors occurred!" << endl; } GUARDED_SCOPE_SUCCESS_END
GUARDED_SCOPE_END } while(0);
GUARDED_SCOPE_END }
int main() {
try { foo(); } catch(exception& e) { cout << "main(): Caught exception: " << e.what() << endl; return -1; }
cout << "main(): No Errors occurred!" << endl; return 0; }
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Why don't you use std::uncaught_exception() instead of exception_thrown?
For a very simple reason. I've missed that one probably due to only resorting to try-catch and Alexandrescu/Loki scopeguards. Did not know that the method existed. Thanks for the tip!
Anyway in real code using a commit variable directly reflects the intent better. Perhaps if I'm wrong, please give a real-world example when your scope guards are more appropriate.
The only benefit is that when you return an error code (without using the return macro), unwind will happen as if an exception had been thrown. This can of course be solved by means of defining and throwing an exception instead of indicating error with negative return code followed by an enclosing try-catch that translates to integer return value. This is only useful when calling a bunch of C-functions that will not, under any circumstances, throw exceptions. It will not add any benefits compared to your example example in a pure C++ design. /Martin

On 17/09/10 11:37, Yakov Galka wrote:
Why don't you use std::uncaught_exception() instead of exception_thrown?
Also in my opinion this is a cleaner solution: void foo() { BOOST_SCOPE_EXIT(empty capture list not supported yet) cout << "Returning from foo()" << endl; if(!std::uncaught_exception()) cout << "foo(): No Errors occurred!" << endl; else cout << "foo(): Exception caught!" << endl; BOOST_SCOPE_EXIT_END // ... }
That won't work in general; std::uncaught_exception might return true because of another pending exception that's going on 'outside' of foo() (e.g. if foo() is called from a destructor). For more details: http://www.gotw.ca/gotw/047.htm John Bytheway

On Friday 17 September 2010 19:56:30 John Bytheway wrote:
On 17/09/10 11:37, Yakov Galka wrote:
BOOST_SCOPE_EXIT(empty capture list not supported yet) cout << "Returning from foo()" << endl; if(!std::uncaught_exception()) cout << "foo(): No Errors occurred!" << endl; else cout << "foo(): Exception caught!" << endl; BOOST_SCOPE_EXIT_END
That won't work in general; std::uncaught_exception might return true because of another pending exception that's going on 'outside' of foo() (e.g. if foo() is called from a destructor).
You could check the function in the constructor of the underlying C++ object, too, in order to detect transitions. That said, the killer phrases for me are these: Martin Christiansson wrote:
GUARDED_SCOPE_SUCCESS() will only run if the function is exited with wrapper for return keyword (GUARDED_SCOPE_RETURN). The wrapper must be used since it updates the hidden guard variables. Using plain "return" will behave as if exception was thrown.
Having to use a big and ugly macro is too intrusive, signaling failure when returning normally is just wrong. Uli

19 sep 2010 kl. 08:59 skrev Ulrich Eckhardt:
Martin Christiansson wrote:
GUARDED_SCOPE_SUCCESS() will only run if the function is exited with wrapper for return keyword (GUARDED_SCOPE_RETURN). The wrapper must be used since it updates the hidden guard variables. Using plain "return" will behave as if exception was thrown.
Having to use a big and ugly macro is too intrusive, signaling failure when returning normally is just wrong.
I've been thinking about a better solution. I need to call a lot of C-functions that use return value and errno for error reporting. Writing a lot of code around each call is a bit clumsy so I tried to create a guard macro instead that puts all relevant data into an exception if the "C function" returned an error. Now it looks like this example with two small silly C-functions: extern "C" { int foo(const char* s) { return strlen(s) - 12; } const char* bar(int n) { return n != 42 ? NULL : "Hello World!"; } } int main() { using boost::lambda::_1; int rc; const char* ptr; try { rc = RETVALGUARD(_1 < 0, foo, "Hello World!"); cout << "rc = " << rc << endl; ptr = RETVALGUARD(_1 == ((char*) NULL), bar, 42); cout << "ptr = " << ptr << endl; } catch (std::exception& e) { cout << (&e)->what() << endl; } return 0; } boost::bind is used when calling the function with it arguments. The return value is evaluated with the conditional expression where _1 is the return value of the C-function. An exception containing return value, errno, function name, file name and line will be thrown if the expression evaluates to true. Now I get a what() that reports: " Exception thrown in retval_guard.cpp at line 65 due to invalid return value from call to foo(): return value = -1, errno = Invalid argument" The macro looks like this: template<typename E, typename T> T conditional_throw_legacy_exception(E cond, T rc, const char* file_name, uint32_t line, const char* func_name) { if(cond(rc)) { throw legacy_exception<T>(rc, file_name, line, func_name); } return rc; } #define RETVALGUARD(COND, FUNC, ...) \ conditional_throw_legacy_exception(COND, \ boost::bind(FUNC, __VA_ARGS__)(), \ static_cast<const char*>(__FILE__), \ __LINE__, \ static_cast<const char*>(# FUNC)) Still need some code cleanup, but I think it will be quicker to translate from C-style return values to a "legacy exception" than writing the code manually for each function call. It will be cleaner than allowing for return to report error and a very low effort to add the macro guard around all C api calls. /Martin

On Sun, Sep 19, 2010 at 08:59, Ulrich Eckhardt <doomster@knuut.de> wrote:
On Friday 17 September 2010 19:56:30 John Bytheway wrote:
[...]
That won't work in general; std::uncaught_exception might return true because of another pending exception that's going on 'outside' of foo() (e.g. if foo() is called from a destructor).
Thank you for the info about std::uncaught_exception. I've never actually used it. You could check the function in the constructor of the underlying C++
object, too, in order to detect transitions.
Checking in the constructor won't detect transitions. If foo() is called from a destructor during stack unwinding, then std::uncaught_exception() will return true twice, even if foo() terminated by yet another exception. Well, this could work if std::uncaught_exception had returned the number of pending exceptions. Could be a useful addition to the standard. On Sun, Sep 19, 2010 at 10:40, Martin Christiansson < martin.christiansson@gmail.com> wrote:
I've been thinking about a better solution. I need to call a lot of C-functions that use return value and errno for error reporting. Writing a lot of code around each call is a bit clumsy so I tried to create a guard macro instead that puts all relevant data into an exception if the "C function" returned an error.
If you're to make it a library, it's better to generalize for other APIs. E.g. use GetLastError() instead of errno for Windows API. #define RETVALGUARD(COND, FUNC, ...)
\ conditional_throw_legacy_exception(COND, \ boost::bind(FUNC, __VA_ARGS__)(), \ static_cast<const char*>(__FILE__), \ __LINE__, \ static_cast<const char*>(# FUNC))
Excuse me if I'm wrong again, but why use boost::bind? Why (FUNC)(__VA_ARGS__) won't work?

I've been thinking about a better solution. I need to call a lot of C-functions that use return value and errno for error reporting. Writing a lot of code around each call is a bit clumsy so I tried to create a guard macro instead that puts all relevant data into an exception if the "C function" returned an error.
If you're to make it a library, it's better to generalize for other APIs. E.g. use GetLastError() instead of errno for Windows API.
Good input! I'm only developing in linux and mac os and lack knowledge about windows API:s. I'll experiment a bit more and evaluate how useful it is.
Excuse me if I'm wrong again, but why use boost::bind? Why (FUNC)(__VA_ARGS__) won't work?
It does work. I no longer need to use bind. The code has evolved a bit from my first attempts and this was remains from the first version. /Martin

On Sunday 19 September 2010 10:40:16 Martin Christiansson wrote:
I need to call a lot of C-functions that use return value and errno for error reporting. Writing a lot of code around each call is a bit clumsy so I tried to create a guard macro instead that puts all relevant data into an exception if the "C function" returned an error.
Sounds sensible. Generally though, I would still not use macros for that unless there's a good reason.
Now it looks like this example with two small silly C-functions:
extern "C" { int foo(const char* s) { return strlen(s) - 12; } const char* bar(int n) { return n != 42 ? NULL : "Hello World!"; } }
int main() { using boost::lambda::_1;
int rc; const char* ptr;
try { rc = RETVALGUARD(_1 < 0, foo, "Hello World!"); cout << "rc = " << rc << endl;
ptr = RETVALGUARD(_1 == ((char*) NULL), bar, 42); cout << "ptr = " << ptr << endl;
} catch (std::exception& e) { cout << (&e)->what() << endl; }
return 0; }
I'd do this: int const x = foo("Hello Christian!"); if(x < 0) throw_errno_exception("foo"); // use x ... Of course, if you want to pack things like __FILE__ and __LINE__, then you will need to use macros.
boost::bind is used when calling the function with it arguments.
Now this is a show-stopper for me, because bind creates a function object which implies copying the arguments, storing them somewhere, and that "somewhere" is possibly dynamically allocated, just to throw them away after the call. This is an insane overhead IMHO, though I'm doing embedded stuff and being mindful of resources is a must there, sometimes even at the expense of being able to debug something. YMMV. What you gain is that you can flexibly define what constitutes failure. Otherwise, you would need an overloaded function that checks the result, provided the same returntype always has the same success/failure meaning. I'd still challenge the advantage of any such solution over writing wrappers: namespace wrapped { int foo(char const* s) { int x = ::foo(s); if(x < 0) throw_errno_exception("foo"); return x; } // ditto for bar() } This has the advantage that you don't repeat the checking code wherever you need to call foo(). Also, unless you call the original, you won't be able to forget checking for errors either, as the checking is done in exactly one place where it also won't clutter your program flow: int main() { try { int const rc = wrapped::foo("Hello World!"); cout << "rc = " << rc << endl; char const* ptr = wrapped::bar(42); cout << "ptr = " << ptr << endl; } catch(std::exception const& e) { cout << e.what() << endl; } } Here you have zero error checking in the code, just the program logic.
} catch (std::exception& e) { cout << (&e)->what() << endl; ^^^^^^ what()? =D
Still need some code cleanup, but I think it will be quicker to translate from C-style return values to a "legacy exception" than writing the code manually for each function call.
But that's what you are doing! You _are_ repeating the error checking code for every call, only that you use a different syntax. Sorry for shredding your design, I hope that you still gain something from it. Uli

boost::bind is used when calling the function with it arguments.
Now this is a show-stopper for me, because bind creates a function object
Not actually needed. Went through that in an earlier reply.
I'd still challenge the advantage of any such solution over writing wrappers:
That would be an option if there where a few functions that needed wrappers or at least that they rarely change their argument list. That is not the case for me. Reducing the number of lines of code to write is important.
} catch (std::exception& e) { cout << (&e)->what() << endl; ^^^^^^ what()? =D
What can I say... I like pointers. No, seriously... Feel free to replace with e.what().
Still need some code cleanup, but I think it will be quicker to translate from C-style return values to a "legacy exception" than writing the code manually for each function call.
But that's what you are doing! You _are_ repeating the error checking code for every call, only that you use a different syntax.
The main issue is to reduce the amount of code to write and maintain since the number of functions is considerable and a moving target. A change in the C-API:s will only require a change to the line where it's called. A wrapper would add an additional part of code to write and maintain. Added cost that is hard to justify to the one who's paying the bill. Added time to a project is even worse. /Martin

On Fri, Sep 17, 2010 at 3:06 AM, Martin Christiansson <martin.christiansson@gmail.com> wrote:
Hi,
I have used the good old scopeguard in the past and recently done some experiments with the Boost.ScopeExit library. Still I feel that the clean scope statements in D is missing.
It will not be possible to do an equally clean solution without having the same features in the language itself, but I could reach as far as this example that reuses the ScopeExit library:
void foo() { GUARDED_SCOPE_BEGIN
GUARDED_SCOPE_EXIT() { cout << "Returning from foo()" << endl; } GUARDED_SCOPE_EXIT_END
GUARDED_SCOPE_SUCCESS() { cout << "foo(): No Errors occurred!" << endl; } GUARDED_SCOPE_SUCCESS_END
GUARDED_SCOPE_FAILURE() { cout << "foo(): Exception caught!" << endl; } GUARDED_SCOPE_FAILURE_END
GUARDED_SCOPE_END }
I looked at what can be done with Boost.ScopeExit and/or Boost.Local exits (they offer essentially the same functionality in this context). 1. SCOPE EXIT First of all, note that Boost.ScopeExit code (and therefore, Boost.Local exit code) is *not* executed when throwing an exception: #include <boost/scope_exit.hpp> #include <iostream> #include <stdexcept> void f() { bool error = false; BOOST_SCOPE_EXIT( (&error) ) { std::cout << "returning" << std::endl; // Not executed on throw. } BOOST_SCOPE_EXIT_END throw std::runtime_error("some error"); } int main() { f(); return 0; } This will *not* print "returning" because the throw terminates `f()` *without* executing local variables' destructors (which execute the scope exit code). 2. ERROR NUMBERS If instead of throwing, `f()` returns an error number (e.g., 0 if success, etc) then `f()` can set a local variable `error` before returning and the local exit code can check `error` to implement D-style scope guards: #include <boost/local/exit.hpp> #include <iostream> int f() { int error = 0; // No error to start with. BOOST_LOCAL_EXIT( (void) ) { // Same as D's `scope(exit)`. std::cout << "exit" << std::endl; } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (const bind& error) ) { // Sane as D's `scope(success)`. if (!error) std::cout << "success" << std::endl; } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (const bind& error) ) { // Same as D's `scope(failure)`. if (error) std::cout << "failure" << std::endl; } BOOST_LOCAL_EXIT_END // Cannot use `return <NUMBER>` otherwise scope exits do not know the // error number. Set error and exit using `return error` instead. error = -2; return error; error = -1; return error; } int main() { std::cout << "error number: " << f() << std::endl; return 0; } 3. EXCEPTIONS If `f()` throws, the situation is more complex. One approach could be to program the 1st local exit to throw the exception while the function code sets the `exception_error` object and returns instead of throwing: #include <boost/local/exit.hpp> #include <iostream> #include <stdexcept> struct exception_error_interface { virtual operator bool() const = 0; virtual void throw_if() const = 0; }; template<typename E> struct exception_error: exception_error_interface { template<typename A0> explicit exception_error(A0 arg0): ex_(E(arg0)) {} template<typename A0, typename A1> exception_error(A0 arg0, A1 arg1): ex_(E(arg0, arg1)) {} // Add more constructors for more parameters if needed... operator bool() const { return true; } void throw_if() const { throw ex_; } private: E ex_; // I need the exception type `E` here so I can throw it later. }; template<> struct exception_error<void> { // Use `void` for no error (cannot throw void). exception_error(): err_() {} // No error by default. template<typename E> // Construct with some error. /* implicit */ exception_error(exception_error<E> const& err): err_(&err) {} template<typename E> // Set some error. exception_error& operator=(exception_error<E> const& err) { err_ = &err; return *this; } operator bool() const { return err_ && bool(*err_); } // Select proper type to throw via polymorphism. void throw_if() const { if (err_) err_->throw_if(); } private: exception_error_interface const* err_; }; void f() { exception_error<void> error; // No error (i.e., `void`) to start with. // This scope exit is special -- it's used to throw on exit if error. BOOST_LOCAL_EXIT( (const bind& error) ) { std::cout << "throwing if error" << std::endl; error.throw_if(); // Throws if error set not to `exception_error<void>`. } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (void) ) { // Smae as D's `scope(exit)`. std::cout << "exit" << std::endl; } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (const bind& error) ) { // Same as D's `scope(success)`. if (!error) std::cout << "success" << std::endl; } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (const bind& error) ) { // Same as D's `scope(failure)`. if (error) std::cout << "failure" << std::endl; } BOOST_LOCAL_EXIT_END // Cannot use `throw` otherwise scope exits are not executed. Set error // and exit using `return` instead (the 1st scope exit will throw). error = exception_error<std::runtime_error>("some error"); return; error = exception_error<int>(-1); return; } int main() { f(); return 0; } The difficulty is to program `exception_error` to actually throw the correct exception type. This is done by storing the exception type `E` and object within the `exception_error<E>` template and then using polymorphism of the virtual function `throw_if()` to select the correct `exception_error` object that should throw (which ultimately throws the exception of the correct stored type `E`). 4. NOTES This approach does not require any extra library support -- Boost.ScopeExit and/or Boost.Local exits are sufficient the way they are. However, it does require programmers to use the local variable `error` instead of returning the error number or throwing the exception directly. However, I do not think the user code looks cluttered from the code that manages `error`. On Sun, Sep 19, 2010 at 7:43 AM, Ulrich Eckhardt <doomster@knuut.de> wrote:
On Sunday 19 September 2010 10:40:16 Martin Christiansson wrote: [...]
boost::bind is used when calling the function with it arguments.
Now this is a show-stopper for me, because bind creates a function object which implies copying the arguments, storing them somewhere, and that "somewhere" is possibly dynamically allocated, just to throw them away after the call. This is an insane overhead IMHO, though I'm doing embedded stuff and being mindful of resources is a must there, sometimes even at the expense of being able to debug something. YMMV.
The `exception_error` approach does not use `bind` but it does add overhead (the virtual functions, etc). However, if programmers are _really_ concerned about performances, they might decide to use error codes instead of exceptions in the first place... or simply not to use the above approach. I could add a sketch of these examples into the Boost.Local docs. What do you think? Thanks. -- Lorenzo

On 3/5/2011 4:24 PM, Lorenzo Caminiti wrote: [...]
1. SCOPE EXIT
First of all, note that Boost.ScopeExit code (and therefore, Boost.Local exit code) is *not* executed when throwing an exception:
#include<boost/scope_exit.hpp> #include<iostream> #include<stdexcept>
void f() { bool error = false;
BOOST_SCOPE_EXIT( (&error) ) { std::cout<< "returning"<< std::endl; // Not executed on throw. } BOOST_SCOPE_EXIT_END
throw std::runtime_error("some error"); }
int main() { f(); return 0; }
This will *not* print "returning" because the throw terminates `f()` *without* executing local variables' destructors (which execute the scope exit code). [...]
Wait...I thought that was the point of Boost.ScopeExit? Aren't the destructors of local variables always invoked during stack unwinding? - Jeff

Jeffrey Lee Hellrung, Jr. wrote:
On 3/5/2011 4:24 PM, Lorenzo Caminiti wrote: [...]
1. SCOPE EXIT
First of all, note that Boost.ScopeExit code (and therefore, Boost.Local exit code) is *not* executed when throwing an exception:
#include<boost/scope_exit.hpp> #include<iostream> #include<stdexcept>
void f() { bool error = false;
BOOST_SCOPE_EXIT( (&error) ) { std::cout<< "returning"<< std::endl; // Not executed on throw. } BOOST_SCOPE_EXIT_END
throw std::runtime_error("some error"); }
int main() { f(); return 0; }
This will *not* print "returning" because the throw terminates `f()` *without* executing local variables' destructors (which execute the scope exit code). [...]
Wait...I thought that was the point of Boost.ScopeExit? Aren't the destructors of local variables always invoked during stack unwinding?
On NetBSD 5.99.47 with gcc 4.1.3: $ g++ -I /home/alnsn/src/boost/trunk /tmp/x.cpp && ./a.out terminate called after throwing an instance of 'std::runtime_error' what(): some error Abort (core dumped) However, if you catch it, you'll see "returning". Alex

On 3/6/2011 9:42 AM, Jeffrey Lee Hellrung, Jr. wrote:
On 3/5/2011 4:24 PM, Lorenzo Caminiti wrote:
This will *not* print "returning" because the throw terminates `f()` *without* executing local variables' destructors (which execute the scope exit code).
[...]
Wait...I thought that was the point of Boost.ScopeExit? Aren't the destructors of local variables always invoked during stack unwinding?
Not if main exits via an uncaught exception. Then all bets are off. Lorenzo is misinformed about the behaviors of ScopeExit and of C++. -- Eric Niebler BoostPro Computing http://www.boostpro.com

On Sun, Mar 6, 2011 at 6:10 AM, Eric Niebler <eric@boostpro.com> wrote:
On 3/6/2011 9:42 AM, Jeffrey Lee Hellrung, Jr. wrote:
On 3/5/2011 4:24 PM, Lorenzo Caminiti wrote:
This will *not* print "returning" because the throw terminates `f()` *without* executing local variables' destructors (which execute the scope exit code).
[...]
Wait...I thought that was the point of Boost.ScopeExit? Aren't the destructors of local variables always invoked during stack unwinding?
Not if main exits via an uncaught exception. Then all bets are off.
Yes, of course this is true (and it doesn't take anything away from the usefulness of Boost.ScopeExit or Boost.Local exits). However, the point is more about how D works than how C++ works because the original author of this email thread was trying to emulate D-style scope guards. I am not a D programmer (so help me here :) ), but I tried this code and it looked like D executes the scope exit even when main() doesn't catch: import std.stdio; void f() { scope(exit) { writeln("returning"); } throw new Exception("some error"); } int main() { // Doesn't catch Exception but still prints "returning" (differently from C++ when using ScopeExit or Local exits). f(); return 0; } E:\sandbox\boost-sandbox\local\libs\local\example>c:\d\dmd2\windows\bin\dmd ex00 .d E:\sandbox\boost-sandbox\local\libs\local\example>ex00 returning object.Exception@ex00.d(9): some error Therefore, I was trying to address also this case to mimic D behavior. Shall I ignore this case and require main() to always catch for the C++ emulations of D-style scope guards to work? Thanks. -- Lorenzo

On 06.03.2011, at 16:05, Lorenzo Caminiti wrote:
Shall I ignore this case and require main() to always catch for the C++ emulations of D-style scope guards to work?
I don't think you have a choice. You *cannot* guarantee code execution upon an uncaught exception, at least not portably. Sebastian

On Sun, Mar 6, 2011 at 1:54 PM, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
On 06.03.2011, at 16:05, Lorenzo Caminiti wrote:
Shall I ignore this case and require main() to always catch for the C++ emulations of D-style scope guards to work?
I don't think you have a choice. You *cannot* guarantee code execution upon an uncaught exception, at least not portably.
I see. Then I would simply declare an `error` local variable and add an extra instruction to set it before throwing: #include <boost/local/exit.hpp> #include <iostream> #include <stdexcept> void f() { bool error = false; // No error to start with. BOOST_LOCAL_EXIT( (void) ) { // Smae as D's `scope(exit)`. std::cout << "exit" << std::endl; } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (const bind& error) ) { // Same as D's `scope(success)`. if (!error) std::cout << "success" << std::endl; } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (const bind& error) ) { // Same as D's `scope(failure)`. if (error) std::cout << "failure" << std::endl; } BOOST_LOCAL_EXIT_END error = true; throw std::runtime_error("some error"); // Must set error. } int main() { // Program cannot terminate with uncaught exception (otherwise local exits // code is not guaranteed to be executed). try { f(); return 0; } catch(...) { return -1; } } And similarly for error numbers instead of exceptions: #include <boost/local/exit.hpp> #include <iostream> int f() { int error = 0; // No error to start with. BOOST_LOCAL_EXIT( (void) ) { // Same as D's `scope(exit)`. std::cout << "exit" << std::endl; } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (const bind& error) ) { // Sane as D's `scope(success)`. if (!error) std::cout << "success" << std::endl; } BOOST_LOCAL_EXIT_END BOOST_LOCAL_EXIT( (const bind& error) ) { // Same as D's `scope(failure)`. if (error) std::cout << "failure" << std::endl; } BOOST_LOCAL_EXIT_END return error = -1; // Must set error. } int main() { return f(); } IMO, this is a clean and simple way to provide D-style scope guards. -- Lorenzo
participants (9)
-
Alexander Nasonov
-
Eric Niebler
-
Jeffrey Lee Hellrung, Jr.
-
John Bytheway
-
Lorenzo Caminiti
-
Martin Christiansson
-
Sebastian Redl
-
Ulrich Eckhardt
-
Yakov Galka