Request for review: scope_exit

I uploaded version 0.01 of scope_exit. It doesn't have tests and a documentation yet (only README.scope_exit) but I'm pretty sure I'll finish them before the review. The library can be downloaded from http://tinyurl.com/y58k33 I attached README.scope_exit. Please review it. There are some problems that may be interested to other people. One related to boost.typeof and another to faster mt code (spin-locks, lock-free whatever). -- Alexander Nasonov http://nasonov.blogspot.com The will of the people is the only legitimate foundation of any government, and to protect its free expression should be our first object. Thomas Jefferson This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$//' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

Perhaps I'm missing something (in which case it might help if you stated your goals more clearly), but I'm not sure it needs to be quite so complicated. Here's what I've done, in the past. First, a usage example: glob_t result_glob; BOOST_FINALLY__BEGIN { globfree( &result_glob ); } BOOST_FINALLY__END int err = glob( pattern.c_str(), flags_glob, NULL, &result_glob ); if (err == 0) { ... return result; } else throw CGlobError( "Glob error" ); // Whether we exited via throw or return, globfree() was // called, avoiding a possible memory leak. The implementation is simply: #define BOOST_FINALLY__BEGIN BOOST_FINALLY__BEGIN__INTERNAL1( __LINE__ ) #define BOOST_FINALLY__BEGIN__INTERNAL1( uniq ) BOOST_FINALLY__BEGIN__INTERNAL2( uniq ) #define BOOST_FINALLY__BEGIN__INTERNAL2( uniq ) \ struct boost_finally_##uniq \ { \ ~boost_finally_##uniq() \ { //! Ends an BOOST_FINALLY block (see BOOST_FINALLY__BEGIN, for details). #define BOOST_FINALLY__END BOOST_FINALLY__END__INTERNAL1( __LINE__ ) #define BOOST_FINALLY__END__INTERNAL1( uniq ) BOOST_FINALLY__END__INTERNAL2( uniq ) #define BOOST_FINALLY__END__INTERNAL2( uniq ) \ } \ } boost_finally_inst_##uniq UNUSED; Where UNUSED is defined as (for gcc): #define UNUSED __attribute__ ((__unused__)) And the explanation: The basic idea is to use the destructor of an instance of a local struct as the mechanism through which the "at scope exit" code gets invoked. In order to facilitate multiple such blocks in the same scope, type and variable names are made unique by appending the source file line number to both names. To avoid compiler warnings that these variables are unused, GCC's 'unused' attribute is applied. For simplicity, I just used my own definition, here. I should note that this was designed for use in functions, only. Also, there are some cases in which I've found this unsatisfactory, and have defined my own scoped_ptr-inspired templates that, upon destruction, call a user-specified function. Matt Alexander Nasonov wrote:

Matt Gruenke wrote:
BEGIN/END variant of BOOST_SCOPE_EXIT exits but I like it less because POSSIBLY SMALL code IS SURROUNDED by capital letters: BOOST_SCOPE_EXIT_BEGIN( (result_glob) ) { globfree( &result_glob ); } BOOST_SCOPE_EXIT_END; It's strange that your code compiles because $ tail -n 8 finally.cpp int main() { int a, b; BOOST_FINALLY__BEGIN { a + b; } BOOST_FINALLY__END } $ g++ finally.cpp finally.cpp: In destructor `main()::boost_finally_25::~boost_finally_25()': finally.cpp:26: error: use of `auto' variable from containing function finally.cpp:24: error: `int a' declared here finally.cpp:26: error: use of `auto' variable from containing function finally.cpp:24: error: `int b' declared here So, you can use only global or static variables inside the block.
SCOPE_EXIT is based on the same idea.
I should note that this was designed for use in functions, only. Also, there are some cases in which I've found this unsatisfactory, ...
Can you be more specific about these? -- Alexander Nasonov http://nasonov.blogspot.com Take away love and our earth is a tomb. Robert Browning This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$//' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

FWIW, another interface could be a class like : // untested class scope_guard { public: typedef boost::function<void()> func_type; explicit scope_guard() { } explicit scope_guard(const func_type& f) { add_function(f); } ~scope_guard() { for(int i = 0; i < m_functions.size(); ++i) m_functions[i](); } void add_function(const func_type& f) { m_functions.push_back(f); } // Could be used to cancel something void clear() { m_functions.clear(); } private: std::vector<func_type> m_functions; }; This, used along with boost::bind would make your example become smth like : glob_t result_glob; scope_guard guard(boost::bind(&globfree, &result_glob)); /* throw or return here */ And you could add more than one function call to do with the add_function() member... of course it's more limited than what your interface offers, but I think the idea is worth mentionning. Credits goes to Eelis (irc) for the idea. Philippe

Philippe Vaucher wrote:
See also <boost/multi_index/detail/scope_guard.hpp>.
Try to construct a guard for more complex case: void foo(std::map<char,int>& codes, char symbol, int code) { bool cancel = codes.insert(std::make_pair(symbol, code)).second; { BOOST_SCOPE_EXIT( (cancel)(codes)(symbol) ) { if(cancel) codes.erase(symbol); }} _; // ... cancel = false; // All is fine at this point, commit. } Problem 1: if. You should use boost::lambda. Problem 2: overloaded erase. I don't think that many developers will wrap erase. They need straitforward solution that doesn't require opening lambda docs, looking for _1->* or bind constructs, trying to figure out why _1->* &std::map<char,int>::erase doesn't work and so on. Problem 3: you can set breakpoint at codes.erase(symbol) line but how do you set it in scope_guard (conditional breakpoint in ~scope_guard with this == &guard stops even if cancel == false)? -- Alexander Nasonov http://nasonov.blogspot.com Float like a butterfly, sting like a bee. Muhammad Ali This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$//' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote
participants (3)
-
Alexander Nasonov
-
Matt Gruenke
-
Philippe Vaucher