try... catch... finally?

Hi, You've probably seen "modern" languages that incorporate the keyword finally, but nothing such exists in C++. I've come with a simple class that could perform close to that keyword. The main exception is that you have to define what finally does BEFORE the try catch clause, which is kind of counter-intuitive but not hurtful. The obvious advantages of such a class over a smart_ptr<X> (X could be void*) is that you can use Boost.Bind (cf my code sample), and the order of the instructions in the finally "clause" is predictable (which is IIRC not guaranteed on destruction of variables). Obviously, though, one could not throw inside a finally... Is such a concept existent currently in Boost (or any library)? If not, would it be useful? I think so, but eh could be wrong :) Hans Larsen ---------------- #include <boost/lambda/lambda.hpp> #include <boost/bind.hpp> #include <iostream> #include <vector> class finally { protected: struct helper_base_t { virtual ~helper_base_t() {} }; template< class T > struct helper_t : public helper_base_t { const T& _; helper_t( const T& t ) : _(t) { } ~helper_t() { _(); } }; std::vector< helper_base_t* > vec; public: finally() {} ~finally() { for( std::vector<helper_base_t*>::iterator it = vec.begin(); it != vec.end(); it++ ) delete (*it); } template< class T > void operator()( const T& t ) { vec.push_back( new helper_t<T>(t) ); } }; struct func1 { void operator()() const { std::cout << 1 << std::endl; } }; void func2( int& x ) { std::cout << x << std::endl; x++; } void function() { using namespace boost; using boost::lambda::var; finally f; int x = 0; f( func1() ); // Simply print 1 // This way we can pass parameters between calls... f( bind( func2, ref(x) ) ); // using Boost.Bind, modify x - will print 0. f( bind( func2, ref(x) ) ); // using Boost.Bind, modify x - will print 1 f( var(x) = 5 ); // using Boost.Bind && Boost.Lambda f( bind( func2, ref(x) ) ); // using Boost.Bind, modify x - will print 5 try { throw int(5); } catch( short x ) { std::cout << (x+1) << std::endl; } } int main() { try { function(); } catch( int x ) { std::cout << x << std::endl; } return 0; }

Hans Larsen wrote:
Hi,
You've probably seen "modern" languages that incorporate the keyword finally, but nothing such exists in C++. I've come with a simple
I've just announced an update of the ScopeExit library. It's much better than the finally keyword ;-) http://194.6.223.221/~nasonov/scope_exit-0.02/libs/scope_exit/doc/html/ -- Alexander Nasonov http://nasonov.blogspot.com You may delay, but time will not. -- Benjamin Franklin -- 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

Hello, Better is such a big word. You still have to say in which way it is better; readability, efficiency, simplicity, something else? ;-) I admit my solution is not perfect, but it does have certain advantages... First, you seem to use boost/typeof/typeof.hpp, which I failed to find in the boost version I currently use (stable 1.33.1). I didn't find the documentation in the full doc, only the BoostBook. Why do you need that library and is it absolutely necessary? I don't think it should from the concepts necessary to put the thing together. All you need, after all, is a destructor to call the code, and some variable passing (Boost.Bind is very wonderful). Also, I'm not a big fan of macros, even more when using IDs in them, I think they reduce readability. I prefer compilers to pre- compilers, if you know what i mean. In your case, adding a scope inside the SCOPE_XXX makes for more indentation, which is not necessarily A Good Thingie. I suggest at least putting those brackets inside the SCOPE_XXX defines. This is all, of course, a matter of taste. BTW, what happens if I typo the ID or just use the same in two different places (either in the same scope or inlined scopes). My solution is CopyConstructable. Many things become interesting when you can copy a chain of commands. It is also bidirectionnal. With a flag at construction, we could invert the order of execution. We could also reorder it in the middle (cannot think of a real use for this, though). BTW, did you check my code? You never told me what you thought of it... Hans PS: I don't think a vector of function calls have been made in boost. I may be wrong On 30-Mar-07, at 7:37 PM, Alexander Nasonov wrote:
Hans Larsen wrote:
Hi,
You've probably seen "modern" languages that incorporate the keyword finally, but nothing such exists in C++. I've come with a simple
I've just announced an update of the ScopeExit library. It's much better than the finally keyword ;-)
http://194.6.223.221/~nasonov/scope_exit-0.02/libs/scope_exit/doc/ html/
-- Alexander Nasonov http://nasonov.blogspot.com
You may delay, but time will not. -- Benjamin Franklin --
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 _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

Hans Larsen wrote:
Hello,
Better is such a big word. You still have to say in which way it is better; readability, efficiency, simplicity, something else? ;-) Readability and simplicity. Compare
std::FILE* f = NULL; try { f = std::fopen("/etc/passwd", "r"); // ... } finally { if(f) std::fclose(f); } with std::FILE* f = std::fopen("/etc/passwd", "r"); scope(exit) { if(f) std::fclose(f); } // ... Even without D's scope(exit) syntax it looks appealing std::FILE* f = std::fopen("/etc/passwd", "r"); BOOST_SCOPE_EXIT(f, (f)) { if(f) std::fclose(f); } BOOST_SCOPE_EXIT_END(f)
I admit my solution is not perfect, but it does have certain advantages...
First, you seem to use boost/typeof/typeof.hpp, which I failed to find in the boost version I currently use (stable 1.33.1). Check it out from cvs or wait for 1.34.
I didn't find the documentation in the full doc, only the BoostBook. It's not in a distribution but you can generate it or read online at http://194.6.223.221/~nasonov/scope_exit-0.02/libs/scope_exit/doc/html/
Why do you need that library and is it absolutely necessary? Because I saw so much exception unaware code.
I don't think it should from the concepts necessary to put the thing together. All you need, after all, is a destructor to call the code, and some variable passing (Boost.Bind is very wonderful).
Bost.Bind and Boost.Lambda are very useful but it's hard to compete with a plain old C++ code. Try to express the 'if(f) std::fclose(f)', for example.
Also, I'm not a big fan of macros, even more when using IDs in them, I think they reduce readability. Me too. But this macro can significantly increase a quality of code.
I prefer compilers to pre- compilers, if you know what i mean. In your case, adding a scope inside the SCOPE_XXX makes for more indentation, which is not necessarily A Good Thingie. SCOPE_EXIT, like _if_ or _while_, controls an execution of a code block.
I suggest at least putting those brackets inside the SCOPE_XXX defines. This is all, of course, a matter of taste. I personally like brackets because they make a small chuck of code surrounded by BIG MACROS more visible. It's also easier to jump between brackets (% in vim) and go to the opening bracket([{ in vim). But if many people don't like brackets, it's a trivial change ...
BTW, what happens if I typo the ID or just use the same in two different places (either in the same scope or inlined scopes).
Typo: hello.cpp: In function `int main()': hello.cpp:18: error: `boost_scope_exit_struct_typo' was not declared in this sco pe hello.cpp:18: error: expected `;' before "const" hello.cpp:18: error: `boost_scope_exit_typo' was not declared in this scope Duplicate id: real_world.cpp:134: error: redefinition of `struct World::addPerson(const Person &)::rollback_boost_scope_exit_nested_typeofold_id' real_world.cpp:121: error: previous definition of `struct World::addPerson(const Person&)::rollback_boost_scope_exit_nested_typeofold_id' Believe me, I don't like id argument either but I couldn't come up with a better solution.
My solution is CopyConstructable. Many things become interesting when you can copy a chain of commands. It is also bidirectionnal. With a flag at construction, we could invert the order of execution. We could also reorder it in the middle (cannot think of a real use for this, though).
BTW, did you check my code? You never told me what you thought of it... I looked at it quickly and noticed dynamic allocations.
This code
template< class T > void operator()( const T& t ) { vec.push_back( new helper_t<T>(t) ); }
is not exception aware. You can rewrite it like this: std::auto_ptr< helper_t<T> > p(new helper_t<T>(t) ); vec.push_back( p.get() ); p.release(); -- Alexander Nasonov http://nasonov.blogspot.com To be pleased with one`s limits is a wretched state. -- Johann Wolfgang von Goethe -- 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

Hello. On 1-Apr-07, at 5:38 PM, Alexander Nasonov wrote:
Hans Larsen wrote:
Hello,
Better is such a big word. You still have to say in which way it is better; readability, efficiency, simplicity, something else? ;-) Readability and simplicity. Compare
std::FILE* f = NULL;
try { f = std::fopen("/etc/passwd", "r"); // ... } finally { if(f) std::fclose(f); }
with
std::FILE* f = std::fopen("/etc/passwd", "r"); scope(exit) { if(f) std::fclose(f); }
// ...
Even without D's scope(exit) syntax it looks appealing
std::FILE* f = std::fopen("/etc/passwd", "r"); BOOST_SCOPE_EXIT(f, (f)) { if(f) std::fclose(f); } BOOST_SCOPE_EXIT_END(f)
Better than finally, yes. I thought you were saying better than my solution ;-)
I admit my solution is not perfect, but it does have certain advantages...
First, you seem to use boost/typeof/typeof.hpp, which I failed to find in the boost version I currently use (stable 1.33.1). Check it out from cvs or wait for 1.34.
Yes, I figured that out :) I'll need to keep a separate copy of those if it is really needed...
I didn't find the documentation in the full doc, only the BoostBook. It's not in a distribution but you can generate it or read online at http://194.6.223.221/~nasonov/scope_exit-0.02/libs/scope_exit/doc/ html/
Why do you need that library and is it absolutely necessary? Because I saw so much exception unaware code.
I don't see any case of valid exceptions in the use of this library. Please point one.
I don't think it should from the concepts necessary to put the thing together. All you need, after all, is a destructor to call the code, and some variable passing (Boost.Bind is very wonderful).
Bost.Bind and Boost.Lambda are very useful but it's hard to compete with a plain old C++ code. Try to express the 'if(f) std::fclose(f)', for example.
With my code? finally f; f( if_then( ref(f), bind(std::fclose, ref(f)) ) ); I admit this solution is less readable than yours, but it's still possible using bind.
Also, I'm not a big fan of macros, even more when using IDs in them, I think they reduce readability. Me too. But this macro can significantly increase a quality of code.
I prefer compilers to pre- compilers, if you know what i mean. In your case, adding a scope inside the SCOPE_XXX makes for more indentation, which is not necessarily A Good Thingie. SCOPE_EXIT, like _if_ or _while_, controls an execution of a code block.
I suggest at least putting those brackets inside the SCOPE_XXX defines. This is all, of course, a matter of taste. I personally like brackets because they make a small chuck of code surrounded by BIG MACROS more visible. It's also easier to jump between brackets (% in vim) and go to the opening bracket([{ in vim). But if many people don't like brackets, it's a trivial change ...
Agreed. Although I don't normally use vim, I know it can be useful (although you could script it ;-).
BTW, what happens if I typo the ID or just use the same in two different places (either in the same scope or inlined scopes).
Typo:
hello.cpp: In function `int main()': hello.cpp:18: error: `boost_scope_exit_struct_typo' was not declared in this sco pe hello.cpp:18: error: expected `;' before "const" hello.cpp:18: error: `boost_scope_exit_typo' was not declared in this scope
Duplicate id:
real_world.cpp:134: error: redefinition of `struct World::addPerson (const Person &)::rollback_boost_scope_exit_nested_typeofold_id' real_world.cpp:121: error: previous definition of `struct World::addPerson(const Person&)::rollback_boost_scope_exit_nested_typeofold_id'
Believe me, I don't like id argument either but I couldn't come up with a better solution.
Why not put the code inside the macro? Example (same as your hello world): #define MY_BOOST_EXIT( w, x, y ) BOOST_SCOPE_EXIT(w, x) \ y \ BOOST_SCOPE_EXIT_END(w) int main() { try { std::string hello("Hello"), world("World"); MY_BOOST_EXIT( _id, (hello)(world), { std::clog << world << ", " << hello << "!\n"; } ) // other code } catch(...) {} /* ^ "World, Hello\n" is printed at this point */ } This way the id is used once. I'm trying to figure out a way to not use the id at all (when constructing local structs). If I find something I'll let you know :)
My solution is CopyConstructable. Many things become interesting when you can copy a chain of commands. It is also bidirectionnal. With a flag at construction, we could invert the order of execution. We could also reorder it in the middle (cannot think of a real use for this, though).
BTW, did you check my code? You never told me what you thought of it... I looked at it quickly and noticed dynamic allocations.
This code
template< class T > void operator()( const T& t ) { vec.push_back( new helper_t<T>(t) ); }
is not exception aware.
You can rewrite it like this: std::auto_ptr< helper_t<T> > p(new helper_t<T>(t) ); vec.push_back( p.get() ); p.release();
mmmh... I fail to see the difference. There is really two cases where exceptions may occur: - operator new( size_t ) throws an exception (Out-Of-Memory). No memory is allocated. - push_back reallocs the vector and operator new( size_t ) throws an exception (Out-Of-Memory). Strong guarantee occurs... (?) Otherwise, my constructor will not throw an exception (by design). If I forget something, point it out to me. I really fail to see how your code is more exception aware than mine, but I'm no exception expert. Have a nice day, Hans
-- Alexander Nasonov http://nasonov.blogspot.com
To be pleased with one`s limits is a wretched state. -- Johann Wolfgang von Goethe --
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 _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

Hans Larsen wrote:
Better than finally, yes. I thought you were saying better than my solution ;-)
No, I said:
It's much better than the finally keyword ;-) because I was replying to the subject rather than to the message.
Why do you need that library and is it absolutely necessary? Because I saw so much exception unaware code.
I don't see any case of valid exceptions in the use of this library. Sorry, I don't understand this statement.
With my code? finally f; f( if_then( ref(f), bind(std::fclose, ref(f)) ) );
I admit this solution is less readable than yours, but it's still possible using bind.
Well, my example is extremely simple. How would you bindify (or lambda-ify) ten lines of ordinary code?
Why not put the code inside the macro?
Example (same as your hello world): #define MY_BOOST_EXIT( w, x, y ) BOOST_SCOPE_EXIT(w, x) \ y \ BOOST_SCOPE_EXIT_END(w)
int main() { try { std::string hello("Hello"), world("World");
MY_BOOST_EXIT( _id, (hello)(world), { std::clog << world << ", " << hello << "!\n"; } )
// other code } catch(...) {} /* ^ "World, Hello\n" is printed at this point */ }
There is a way to avoid _id, see below.
This way the id is used once. I'm trying to figure out a way to not use the id at all (when constructing local structs). If I find something I'll let you know :)
A global or thread-scope variable can be used to save a pointer to an object holding all references (hello and world in the example). Actually, the first version was based on that technique. This code demonstrates how it works under the hood: // Somewhere in the library __thread void* g_args; // User code BOOST_SCOPE_EXIT( (hello)(world) ) // line 1 /* Expands to: struct args_line1 { std::string &hello, &world; } args_line1 = { hello, world }; g_args = &args_line1; struct scope_exit_line1 { void* m_args; ~scope_exit() { struct args_line1* p = (struct args_line1*)m_args; doit(p->hello, p->world); } static void doit(std::string& hello, std::string& world) */ { // scope(exit) code } BOOST_SCOPE_EXIT_END // line 5 /* } scope_exit_line5 = { g_args }; */ Without g_args, it's not easy to know a name of args_line1 at line 5. Although a next instruction after writing to g_args is reading it, thread-safety is a problem and that's why I abandoned this approach.
You can rewrite it like this: std::auto_ptr< helper_t<T> > p(new helper_t<T>(t) ); vec.push_back( p.get() ); p.release();
mmmh... I fail to see the difference. There is really two cases where exceptions may occur: - operator new( size_t ) throws an exception (Out-Of-Memory). No memory is allocated. - push_back reallocs the vector and operator new( size_t ) throws an exception (Out-Of-Memory). Strong guarantee occurs... (?)
- push_back throws, vector doesn't leak but new helper_t<T>(t) is lost.
-- Alexander Nasonov http://nasonov.blogspot.com
To be pleased with one`s limits is a wretched state. -- Johann Wolfgang von Goethe --
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 _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Alexander Nasonov http://nasonov.blogspot.com An inconvenience is only an adventure wrongly considered; an adventure is an inconvenience rightly considered. -- GK Chesterton -- 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

Hello Alexander, Wednesday, April 4, 2007, 12:16:34 AM, you wrote: [snip]
A global or thread-scope variable can be used to save a pointer to an object holding all references (hello and world in the example). Actually, the first version was based on that technique.
This code demonstrates how it works under the hood:
// Somewhere in the library __thread void* g_args;
// User code BOOST_SCOPE_EXIT( (hello)(world) ) // line 1 /* Expands to: struct args_line1 { std::string &hello, &world; } args_line1 = { hello, world }; g_args = &args_line1; struct scope_exit_line1 { void* m_args; ~scope_exit() { struct args_line1* p = (struct args_line1*)m_args; doit(p->hello, p->world); } static void doit(std::string& hello, std::string& world) */ { // scope(exit) code } BOOST_SCOPE_EXIT_END // line 5 /* } scope_exit_line5 = { g_args }; */
Without g_args, it's not easy to know a name of args_line1 at line 5.
Although a next instruction after writing to g_args is reading it, thread-safety is a problem and that's why I abandoned this approach.
What if something like that: BOOST_SCOPE_EXIT // line 1 /* Expands to: struct _scope_guard_class_line1 { ~_scope_guard_class_line1() { */ { // scope(exit) code } BOOST_SCOPE_EXIT_END((hello)(world)); // line 5 /* Expands to: } std::string& hello; std::string& world; } _scope_guard_line5 = { hello, world }; */ While the variable list is now in the end, no ids needed at all. [snip] -- Best regards, Andrey mailto:andysem@mail.ru

Andrey Semashev wrote:
What if something like that:
BOOST_SCOPE_EXIT // line 1 /* Expands to: struct _scope_guard_class_line1 { ~_scope_guard_class_line1() { */ { // scope(exit) code } BOOST_SCOPE_EXIT_END((hello)(world)); // line 5 /* Expands to: }
std::string& hello; std::string& world; } _scope_guard_line5 = { hello, world }; */
While the variable list is now in the end, no ids needed at all.
I considered it too but I thought it could scare people. So, we have 1. BOOST_SCOPE_EXIT { // ... } BOOST_SCOPE_EXIT_END( (hello)(world) ) 2. BOOST_SCOPE_EXIT(id, (hello)(world) ) { // ... } BOOST_SCOPE_EXIT_END(id) 3. with global variable BOOST_SCOPE_EXIT( (hello)(world) ) { // ... } BOOST_SCOPE_EXIT_END I even considered something like this in the past: { BOOST_SCOPE_EXIT( (hello)(world) { // code }} id; It may seem strange but not to people familiar with ruby blocks: { |hello,world| // code } -- Alexander Nasonov http://nasonov.blogspot.com Don`t knock masturbation; it`s sex with someone I love. -- Woody Allen -- 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

On 3-Apr-07, at 6:52 PM, Alexander Nasonov wrote:
Andrey Semashev wrote:
What if something like that:
BOOST_SCOPE_EXIT // line 1 /* Expands to: struct _scope_guard_class_line1 { ~_scope_guard_class_line1() { */ { // scope(exit) code } BOOST_SCOPE_EXIT_END((hello)(world)); // line 5 /* Expands to: }
std::string& hello; std::string& world; } _scope_guard_line5 = { hello, world }; */
While the variable list is now in the end, no ids needed at all.
I considered it too but I thought it could scare people.
So, we have
1. BOOST_SCOPE_EXIT { // ... } BOOST_SCOPE_EXIT_END( (hello)(world) )
or, putting the code as a parameter to the macro: BOOST_SCOPE_EXIT( (hello)(world), { // ... } );
2. BOOST_SCOPE_EXIT(id, (hello)(world) ) { // ... } BOOST_SCOPE_EXIT_END(id)
3. with global variable BOOST_SCOPE_EXIT( (hello)(world) ) { // ... } BOOST_SCOPE_EXIT_END
What about using a static variable instead? // User code //BOOST_SCOPE_EXIT( (hello)(world) ) // line 1 /* Expands to: */ static struct args_line1_t { std::string &hello, &world; } args_line1 = { hello, world }; struct scope_exit_line1 { ~scope_exit_line1() { struct args_line1_t* p = (struct args_line1_t*)&args_line1; doit(p->hello, p->world); } static void doit(std::string& hello, std::string& world) /**/ { // scope(exit) code } /**/ //BOOST_SCOPE_EXIT_END // line 5 /**/ } scope_exit_line5; /**/ If the variables are on the stack (or inside thread storage), it should be thread-safe, right? Is the use of __LINE__ correct? I can't think of a way to break it, which in no way means it's perfect... Hans Post-Scriptum:
Why do you need that library and is it absolutely necessary? Because I saw so much exception unaware code. I don't see any case of valid exceptions in the use of this library. Sorry, I don't understand this statement.
Simply that BOOST_SCOPE_EXIT( ... ) { throw XXX; } Is invalid by definition. So I don't know why you'd need to be exception aware - or exception whatever in this case. We don't call any external variables and use references, therefore I don't see a case where our own code might throw an exception outside of the client-code. If you're talking about the fact that you need to get an unknown typename into a local-class (how to know that hello and world are std::string, for example), then the typeof dependency is well justified. Otherwise, I still fail to see why it is needed.
I even considered something like this in the past:
{ BOOST_SCOPE_EXIT( (hello)(world) { // code }} id;
It may seem strange but not to people familiar with ruby blocks:
{ |hello,world| // code }

Hello Hans, Wednesday, April 4, 2007, 4:14:14 AM, you wrote:
I considered it too but I thought it could scare people.
So, we have
1. BOOST_SCOPE_EXIT { // ... } BOOST_SCOPE_EXIT_END( (hello)(world) )
or, putting the code as a parameter to the macro:
BOOST_SCOPE_EXIT( (hello)(world), { // ... } );
This may lead to problems if a non-parenthised comma is in the scope exit body. -- Best regards, Andrey mailto:andysem@mail.ru

AMDG I wish there were a portable way to get: BOOST_SCOPE_EXIT { //body } I can make it work for msvc, and the technique can probably be extended to other compilers/platforms but it is not at all nice. In Christ, Steven Watanabe

Steven Watanabe wrote:
I can make it work for msvc How?
-- Alexander Nasonov http://nasonov.blogspot.com Wedding: a ceremony at which two persons undertake to become one, one undertakes to become nothing, and nothing undertakes to become supportable. -- Ambrose Bierce -- 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

Alexander Nasonov <alnsn <at> yandex.ru> writes:
Steven Watanabe wrote:
I can make it work for msvc How?
#include <boost/config.hpp> namespace boost { namespace scope_exit { #if (defined(BOOST_MSVC) && defined(_M_IX86)) || \ (defined(__MWERKS__) && defined(__INTEL__ )) struct jump_buffer { unsigned long return_; unsigned long esp_; unsigned long ebp_; }; extern "C" { __declspec(naked) int __fastcall set_jump(jump_buffer*) { __asm { mov edx, [esp] mov [ecx], edx mov [ecx + 4], esp mov [ecx + 8], ebp mov eax, 0 ret } } __declspec(naked) int __fastcall long_jump(jump_buffer*, int) { __asm { mov ebx, [ecx] mov esp, [ecx + 4] mov ebp, [ecx + 8] mov [esp], ebx mov eax, edx ret } } } #define BOOST_SCOPE_EXIT_USE_REGISTERS __asm {\ __asm mov eax, 0\ __asm mov ebx, 0\ __asm mov ecx, 0\ __asm mov edx, 0\ __asm mov esi, 0\ __asm mov edi, 0\ } struct scope_exit_helper1 { jump_buffer cleanup; jump_buffer back; ~scope_exit_helper1() { BOOST_SCOPE_EXIT_USE_REGISTERS if(set_jump(&back) == 0) { long_jump(&cleanup, 1); } } }; struct scope_exit_helper2 { jump_buffer* buf; scope_exit_helper2(jump_buffer* b) : buf(b) {} ~scope_exit_helper2() { if(buf) { long_jump(buf, 1); } } scope_exit_helper2(const scope_exit_helper2& other) : buf(other.buf) { const_cast<jump_buffer*&>(other.buf) = 0; } operator bool() const { return(false); } }; #define BOOST_SCOPE_EXIT_PROTECT_STACK \ if(true) __asm { \ __asm sub esp, 512 \ __asm jmp boost_scope_exit_label ## __LINE__ \ } \ else boost_scope_exit_label ## __LINE__: #define BOOST_SCOPE_EXIT \ ::boost::scope_exit::scope_exit_helper1 \ boost_scope_exit_helper1 ## __LINE__; \ BOOST_SCOPE_EXIT_USE_REGISTERS \ if(::boost::scope_exit::set_jump( \ &boost_scope_exit_helper1 ## __LINE__.cleanup) == 0) {} \ else BOOST_SCOPE_EXIT_PROTECT_STACK \ if(::boost::scope_exit::scope_exit_helper2\ boost_scope_exit_helper2 = \ (&boost_scope_exit_helper1 ## __LINE__.back)) {}\ else #endif } }

On 4/4/07, Steven Watanabe <steven@providere-consulting.com> wrote:
Alexander Nasonov <alnsn <at> yandex.ru> writes:
Steven Watanabe wrote:
I can make it work for msvc How?
#include <boost/config.hpp>
namespace boost {
namespace scope_exit {
[snipped - asm code]
You forgot it that it can't scale well. Even msvc 8 can output in arm or x64. Now imagine for gcc? -- Felipe Magno de Almeida

AMDG Felipe Magno de Almeida <felipe.m.almeida <at> gmail.com> writes:
You forgot it that it can't scale well. Even msvc 8 can output in arm or x64. Now imagine for gcc?
I didn't forget anything. It isn't quite as bad as it appears since about half the code doesn't need to be duplicated and for some compilers you may be able to use std::setjmp/longjmp. Even so, it's probably not worth the effort. In Christ, Steven Watanabe

Steven Watanabe wrote:
Alexander Nasonov <alnsn <at> yandex.ru> writes:
Steven Watanabe wrote:
I can make it work for msvc How?
#include <boost/config.hpp> ...
I'm very impressed how you wrote it off the top of your head :-> But it's definitely too much magic. Though, it made me think of another magic: study alloca implementations and replace a global variable with something like BOOST_SCOPE_EXIT( (hello)(world) ) // line 1 /* Expands to: struct args_line1 { std::string &hello, &world; } args_line1 = { hello, world }; void** saved_args = (void**)aloca(sizeof(void*)); *saved_args = &args_line1; struct scope_exit_line1 { void* m_args; ~scope_exit() { struct args_line1* p = (struct args_line1*)m_args; doit(p->hello, p->world); } static void doit(std::string& hello, std::string& world) */ { // scope(exit) code } BOOST_SCOPE_EXIT_END // line 5 /* } scope_exit_line5 = { *static_cast<void**>(last_alloca_result()) }; */ The key here is get_alloca_result that returns a value returned by last alloca call. -- Alexander Nasonov http://nasonov.blogspot.com When you`re comfortable with someone you love, the silence is the best. -- Britney Spears -- 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

Alexander Nasonov <alnsn <at> yandex.ru> writes:
I'm very impressed how you wrote it off the top of your head :->
I didn't. I've been toying with it for a couple of days.
But it's definitely too much magic. Though, it made me think of another magic: study alloca implementations and replace a global variable with something like
<snip>
Why do you need this magic? BOOST_SCOPE_EXIT( (hello)(world) ) // line 1 /* Expands to: struct args_line1_t { std::string &hello, &world; } args_line1 = { hello, world }; struct scope_exit_line1 { args_line1_t* m_args; ~scope_exit() { doit(p->hello, p->world); } static void doit(std::string& hello, std::string& world) */ { // scope(exit) code } BOOST_SCOPE_EXIT_END // line 5 /* } scope_exit_line5 = { &args_line1 }; */ In Christ, Steven Watanabe

Hey guys. Very interesting this problem is and the proposed solutions leads one to another :) Problem underlined below. On 4-Apr-07, at 6:27 PM, Steven Watanabe wrote:
Alexander Nasonov <alnsn <at> yandex.ru> writes:
I'm very impressed how you wrote it off the top of your head :->
I didn't. I've been toying with it for a couple of days.
But it's definitely too much magic. Though, it made me think of another magic: study alloca implementations and replace a global variable with something like
<snip>
Why do you need this magic?
BOOST_SCOPE_EXIT( (hello)(world) ) // line 1 /* Expands to: struct args_line1_t { std::string &hello, &world; } args_line1 = { hello, world }; struct scope_exit_line1 { args_line1_t* m_args; ~scope_exit() { doit(p->hello, p->world); } static void doit(std::string& hello, std::string& world) */ { // scope(exit) code } BOOST_SCOPE_EXIT_END // line 5 /* } scope_exit_line5 = { &args_line1 };
How do you know that it is args_line1? You cannot use __LINE__, since it is == 5. Hans
*/
In Christ, Steven Watanabe
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

AMDG Hans Larsen <hans <at> poltras.com> writes:
Hey guys. Very interesting this problem is and the proposed solutions leads one to another :)
Problem underlined below.
How do you know that it is args_line1? You cannot use __LINE__, since it is == 5.
Yeah. Wasn't thinking. Here's a solution that ought to work struct scope_exit_helper { virtual ~scope_exit_helper() {} }; struct scope_exit_helper_test : scope_exit_helper { void *dummy; }; int* i = new int; struct scope_exit_helper1_line1_t {int*& i; } scope_exit_helper1_line1 = { i }; struct scope_exit_helper2_line1_t { ~scope_exit_helper2_line1_t() { helper->~scope_exit_helper(); } scope_exit_helper* helper; boost::aligned_storage<sizeof(scope_exit_helper_test)> storage; } scope_exit_helper2_line1; { scope_exit_helper1_line1_t* in = &scope_exit_helper1_line1; scope_exit_helper2_line1_t* out = &scope_exit_helper2_line1; struct scope_exit_t : scope_exit_helper { scope_exit_t(scope_exit_helper1_line1_t* p) : impl(p) {} scope_exit_helper1_line1_t* impl; ~scope_exit_t() { run(impl->i); } void run(int*& i) { delete i; std::cout << "block exited" << std::endl; } }* scope_exit = static_cast<scope_exit_t*>( static_cast<void*>(out->storage.address())); out->helper = scope_exit; new(scope_exit) scope_exit_t(in); BOOST_STATIC_ASSERT((sizeof(scope_exit_t) == sizeof(scope_exit_helper_test))); } In Christ, Steven Watanabe

AMDG Alexander Nasonov <alnsn <at> yandex.ru> writes:
Steven Watanabe <steven <at> providere-consulting.com> writes:
Yeah. Wasn't thinking. Here's a solution that ought to work Wow! I didn't compile it but the idea is brilliant. I will play with it.
Just as a warning. msvc 8.0 doesn't seem to be able to handle member functions of local classes in functions defined in headers. In Christ, Steven Watanabe

Steven Watanabe wrote:
Just as a warning. msvc 8.0 doesn't seem to be able to handle member functions of local classes in functions defined in headers.
I compiled and ran attached file on vc8, vc71, gcc 3.4 and intel-linux 8.1. -- Alexander Nasonov http://nasonov.blogspot.com Never pick a fight with people who buy ink by the barrel. -- Bill Clinton -- 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

AMDG Alexander Nasonov <alnsn <at> yandex.ru> writes:
Steven Watanabe wrote:
Just as a warning. msvc 8.0 doesn't seem to be able to handle member functions of local classes in functions defined in headers.
I compiled and ran attached file on vc8, vc71, gcc 3.4 and intel-linux 8.1.
The problem is that the linker complains about duplicate definitions. Try using an inline function or template in multiple translation units. msvc 8.0 sp1 won't even let me use __declspec(selectany) In Christ, Steven Watanabe

Steven Watanabe wrote:
The problem is that the linker complains about duplicate definitions. Try using an inline function or template in multiple translation units. msvc 8.0 sp1 won't even let me use __declspec(selectany) I reimplemented the macro and I see the problem but I already made up my mind: use portable solution when possible and rely on asm magic of __thread global on msvc.
-- Alexander Nasonov http://nasonov.blogspot.com I couldn`t tell if the streaker was a man or a woman because it had a bag on it`s head. -- Yogi Berra -- 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

Hello Alexander, Friday, April 6, 2007, 11:00:51 PM, you wrote:
Alexander Nasonov wrote:
I reimplemented the macro and I see the problem but I already made up my mind: use portable solution when possible and rely on asm magic of __thread global on msvc. ^ or Sorry for the typo.
IMHO, asm much is better. __thread has problems in dll and besides, I suspect, is slower. -- Best regards, Andrey mailto:andysem@mail.ru

I don't think the goal is being fast, although that would be a plus. As long as the two solutions don't differ in their uses, I don't care on the implementation, but ASM is not portable, and I better like a less easy to use but same interface on every platform. BOOST_SCOPE_EXIT { // ... } (msc-only) versus BOOST_SCOPE_EXIT( (hello)(world) ) { // ... } (on everything) is a clear choice for me. Hans On 6-Apr-07, at 3:11 PM, Andrey Semashev wrote:
Hello Alexander,
Friday, April 6, 2007, 11:00:51 PM, you wrote:
Alexander Nasonov wrote:
I reimplemented the macro and I see the problem but I already made up my mind: use portable solution when possible and rely on asm magic of __thread global on msvc. ^ or Sorry for the typo.
IMHO, asm much is better. __thread has problems in dll and besides, I suspect, is slower.
-- Best regards, Andrey mailto:andysem@mail.ru
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

Hello Hans, Friday, April 6, 2007, 11:28:46 PM, you wrote:
I don't think the goal is being fast, although that would be a plus.
For me the performance is of high concern. I expect the BOOST_SCOPE_EXIT performance to be comparable to a hand-written scope guard like that: struct guard { ~guard() { // guard body } }; Another thing I expect is the guard's construction error safety. I.e. it may not involve things like dynamic memory allocations, TLS slot acquirement, etc., and should minimize copying of any user's objects.
As long as the two solutions don't differ in their uses, I don't care on the implementation, but ASM is not portable, and I better like a less easy to use but same interface on every platform.
BOOST_SCOPE_EXIT { // ... } (msc-only) versus BOOST_SCOPE_EXIT( (hello)(world) ) { // ... } (on everything) is a clear choice for me.
I guess, the interface may be the same across platforms. I'm fine with the second one you mentioned.
On 6-Apr-07, at 3:11 PM, Andrey Semashev wrote:
Hello Alexander,
Friday, April 6, 2007, 11:00:51 PM, you wrote:
Alexander Nasonov wrote:
I reimplemented the macro and I see the problem but I already made up my mind: use portable solution when possible and rely on asm magic of __thread global on msvc. ^ or Sorry for the typo.
IMHO, asm much is better. __thread has problems in dll and besides, I suspect, is slower.
-- Best regards, Andrey mailto:andysem@mail.ru

Andrey Semashev wrote:
For me the performance is of high concern. I expect the BOOST_SCOPE_EXIT performance to be comparable to a hand-written scope guard like that:
struct guard { ~guard() { // guard body } };
My last solution wraps scope-exit-block into a function, take an address of this function and calls it indirectly. I don't know (yet) if any compiler is able to optimize this call away, though.
Another thing I expect is the guard's construction error safety. I.e. it may not involve things like dynamic memory allocations, TLS slot acquirement, etc., and should minimize copying of any user's objects. It's very lightweight.
-- Alexander Nasonov http://nasonov.blogspot.com When you are arguing against Him you are arguing against the very power that makes you able to argue at all. -- C.S. Lewis -- 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

Alexander, can you upload your last solution to the vault (or send it directly to me) once it works? :) Hans On 6-Apr-07, at 4:16 PM, Alexander Nasonov wrote:
Andrey Semashev wrote:
For me the performance is of high concern. I expect the BOOST_SCOPE_EXIT performance to be comparable to a hand-written scope guard like that:
struct guard { ~guard() { // guard body } };
My last solution wraps scope-exit-block into a function, take an address of this function and calls it indirectly. I don't know (yet) if any compiler is able to optimize this call away, though.
Another thing I expect is the guard's construction error safety. I.e. it may not involve things like dynamic memory allocations, TLS slot acquirement, etc., and should minimize copying of any user's objects. It's very lightweight.
-- Alexander Nasonov http://nasonov.blogspot.com
When you are arguing against Him you are arguing against the very power that makes you able to argue at all. -- C.S. Lewis --
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 _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

See attached file. It works on msvc but only if you don't use BOOST_SCOPE_EXIT in header files. Hans Larsen wrote:
Alexander, can you upload your last solution to the vault (or send it directly to me) once it works? :)
Hans
On 6-Apr-07, at 4:16 PM, Alexander Nasonov wrote:
Andrey Semashev wrote:
For me the performance is of high concern. I expect the BOOST_SCOPE_EXIT performance to be comparable to a hand-written scope guard like that:
struct guard { ~guard() { // guard body } };
My last solution wraps scope-exit-block into a function, take an address of this function and calls it indirectly. I don't know (yet) if any compiler is able to optimize this call away, though.
Another thing I expect is the guard's construction error safety. I.e. it may not involve things like dynamic memory allocations, TLS slot acquirement, etc., and should minimize copying of any user's objects. It's very lightweight.
-- Alexander Nasonov http://nasonov.blogspot.com
When you are arguing against Him you are arguing against the very power that makes you able to argue at all. -- C.S. Lewis --
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 _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Alexander Nasonov http://nasonov.blogspot.com In all chaos there is a cosmos, in all disorder a secret order. -- Carl Jung -- 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

Hans Larsen wrote:
BOOST_SCOPE_EXIT { // ... } (msc-only) I'm not going to implement this. And I'm not even going to study Steven's asm code. Sorry, Steven ;-)
versus BOOST_SCOPE_EXIT( (hello)(world) ) { // ... } (on everything) is a clear choice for me. With BOOST_SCOPE_EXIT_END in the end, it is my favorite at present. It fails on msvc in some cases so I'm going to fix it in non-portable way but a) only for msvc b) with much less asm
What's needed is somehow get a value of ptr without referencing it by name (because it depends on __LINE__ but we don't know its value): params_t params(hello, world); void* ptr = ¶ms; // definitions etc but no stack manipulations scope_exit_t scope_exit = { ptr }; // get rid of ptr here! scope_exit_t has a user-defined dtor and no virtual functions. There is only one memory allocation on the stak after ptr allocation - the scope_exit object construction. May be I could reserve a register at the second line and use it at the last line? Names of registers don't depend on __LINE__! -- Alexander Nasonov http://nasonov.blogspot.com It is never okay to throw away veteran underwear. A real guy checks the garbage regularly in case somebody - and we are not naming names but this would be his wife - is quietly trying to discard his underwear, which she is frankly jealous of, because the guy seems to have a more intimate relationship with it than with her. -- Dave Barry -- 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

Andrey Semashev wrote:
IMHO, asm much is better. __thread has problems in dll and besides, I suspect, is slower. I knew about possible problems (at least one is documented) but I never analyzed performance penalties. -- Alexander Nasonov http://nasonov.blogspot.com
When a man is able to take abuse with a smile, he is worthy to become a leader. -- Nachman of Bratslav -- 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

Steven Watanabe wrote:
Alexander Nasonov <alnsn <at> yandex.ru> writes:
Steven Watanabe wrote:
I can make it work for msvc How?
[BIG snip of the implementation]
but it is not at all nice.
Oh boy! You weren't joking, were you? I'm impressed (but I wouldn't want to have to step through code like that in the debugger). -- Martin Bonner Project Leader PI SHURLOK LTD Telephone: +44 1223 441434 / 203894 (direct) Fax: +44 1223 203999 Email: martin.bonner@pi-shurlok.com www.pi-shurlok.com

Hans Larsen wrote:
or, putting the code as a parameter to the macro:
BOOST_SCOPE_EXIT( (hello)(world), { // ... } );
As Andrey pointed out, any comma inside the block would break your code: BOOST_SCOPE_EXIT( (hello)(world), { a, b; } ) GNU g++ would report something like: macro "BOOST_SCOPE_EXIT" passed 3 arguments, but takes just 2. You could either BOOST_SCOPE_EXIT( (hello)(world), ({ a, b; }) ) or BOOST_SCOPE_EXIT( (hello)(world), { (a, b;) } ) but I don't know how to deal with these strange constructs.
What about using a static variable instead? It has no significant differences with a global variable.
// User code //BOOST_SCOPE_EXIT( (hello)(world) ) // line 1 /* Expands to: */ static struct args_line1_t { std::string &hello, &world; } args_line1 = { hello, world };
It's incorrect, args_line1 is initialized only once and never changes. It always points to hello and world existed when a program reached this point the first time.
Is the use of __LINE__ correct? I can't think of a way to break it, which in no way means it's perfect... It's correct unless you put more than one scope(exit) in one line.
Why do you need that library and is it absolutely necessary? Because I saw so much exception unaware code. I don't see any case of valid exceptions in the use of this library. Sorry, I don't understand this statement.
Simply that BOOST_SCOPE_EXIT( ... ) { throw XXX; }
Is invalid by definition. Indeed, it's almost always invalid. I would never throw from inside of a scope(exit) block. But I was talking about exception unware code in pre scope(exit) era. Developers often don't cleanup resources if an exception is thrown. The library would help here.
If you're talking about the fact that you need to get an unknown typename into a local-class (how to know that hello and world are std::string, for example), then the typeof dependency is well justified. Otherwise, I still fail to see why it is needed.
Yes, typeof is there to bring types of variables into the class. -- Alexander Nasonov http://nasonov.blogspot.com Government does not tax to get the money it needs; government always finds a need for the money it gets. -- Ronald Reagan -- 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

Hello Alexander, Thursday, April 5, 2007, 12:41:49 AM, you wrote:
Is the use of __LINE__ correct? I can't think of a way to break it, which in no way means it's perfect... It's correct unless you put more than one scope(exit) in one line.
It breaks on VC 7.0+ with /ZI option. Use __COUNTER__ instead. -- Best regards, Andrey mailto:andysem@mail.ru

On 4/1/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
Hans Larsen wrote:
Hello,
Better is such a big word. You still have to say in which way it is better; readability, efficiency, simplicity, something else? ;-) Readability and simplicity. Compare
std::FILE* f = NULL;
try { f = std::fopen("/etc/passwd", "r"); // ... } finally { if(f) std::fclose(f); }
with
std::FILE* f = std::fopen("/etc/passwd", "r"); scope(exit) { if(f) std::fclose(f); }
// ...
Even without D's scope(exit) syntax it looks appealing
std::FILE* f = std::fopen("/etc/passwd", "r"); BOOST_SCOPE_EXIT(f, (f)) { if(f) std::fclose(f); } BOOST_SCOPE_EXIT_END(f)
Well, I'm very late to this thread of discussion, but I'd like to add my $0.02. Why would we go through so much complexity? Remember the simple and basic principle of RAII? In situations like this, you just make a simple wrapper of the FILE*, with an implementation similar to that of a smart pointer such as the auto_ptr, and let's name it auto_cfile, with a "FILE*&()" operator member function to expose the FILE* it protects: auto_cfile f(std::fopen("/etc/passwd","r")); .... (uses of f as if it were a FILE*) and the FILE* is automatically closed by auto_cfile's dtor when it goes out of scope. No need of a "try ... catch" block at all, much less of "finally," which is an unnecessary addition in C#, IMHO. <snip> --
Alexander Nasonov http://nasonov.blogspot.com
<snip> -- Thanks, Greg

I totally agree. I used to think about the lack of the finally keyword in C++ and after reading, pondering and implementing I found that RAII is always just a so much better solution and saves you from having writing so many scoped blocks of code and local variables to hold state information etc. For example one can even write a "very simple" RAII class for FILE* and THIS is the only time I allow approve usage of an "ugly" public member data BECAUSE this is not a fully fledged wrapper class and writing one takes time. This scenario is even more presentful on Windows because of enormous amount of COM variables that one may have to wrap... ifndef utility_h define utility_h class File { public: // YES ugly pubic member data because this is not a fully fledged class... FILE *Handle; File() { Handle = NULL; } File(const std::string &filename, const std::string &mode) { Handle = fopen(filename.c_str(), mode.c_str(); if(ferror(Handle)) { throw std::exception("fopen failed"); } } ~File() { if(Handle) { fclose(Handle); } } }; endif void OpenFileAfterSelection() { File f("/somefilename", "r+w"); while(fgets(f.handle, somebuffer, sizeof(somebuffer)) { // do something and maybe throw exceptions.... } // AND regardless of exceptions or success ~f() always runs } Thanks Shams -- "Gregory Dai" <gregory.dai@gmail.com> wrote in message news:ce347e580704081736k661c2c03vae674ee11490539c@mail.gmail.com...
On 4/1/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
Hans Larsen wrote:
Hello,
Better is such a big word. You still have to say in which way it is better; readability, efficiency, simplicity, something else? ;-) Readability and simplicity. Compare
std::FILE* f = NULL;
try { f = std::fopen("/etc/passwd", "r"); // ... } finally { if(f) std::fclose(f); }
with
std::FILE* f = std::fopen("/etc/passwd", "r"); scope(exit) { if(f) std::fclose(f); }
// ...
Even without D's scope(exit) syntax it looks appealing
std::FILE* f = std::fopen("/etc/passwd", "r"); BOOST_SCOPE_EXIT(f, (f)) { if(f) std::fclose(f); } BOOST_SCOPE_EXIT_END(f)
Well, I'm very late to this thread of discussion, but I'd like to add my $0.02.
Why would we go through so much complexity? Remember the simple and basic principle of RAII? In situations like this, you just make a simple wrapper of the FILE*, with an implementation similar to that of a smart pointer such as the auto_ptr, and let's name it auto_cfile, with a "FILE*&()" operator member function to expose the FILE* it protects:
auto_cfile f(std::fopen("/etc/passwd","r")); .... (uses of f as if it were a FILE*)
and the FILE* is automatically closed by auto_cfile's dtor when it goes out of scope.
No need of a "try ... catch" block at all, much less of "finally," which is an unnecessary addition in C#, IMHO.
<snip>
--
Alexander Nasonov http://nasonov.blogspot.com
<snip>
-- Thanks, Greg _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hello Gregory, Monday, April 9, 2007, 4:36:36 AM, you wrote:
Well, I'm very late to this thread of discussion, but I'd like to add my $0.02.
Why would we go through so much complexity? Remember the simple and basic principle of RAII? In situations like this, you just make a simple wrapper of the FILE*, with an implementation similar to that of a smart pointer such as the auto_ptr, and let's name it auto_cfile, with a "FILE*&()" operator member function to expose the FILE* it protects:
auto_cfile f(std::fopen("/etc/passwd","r")); ..... (uses of f as if it were a FILE*)
and the FILE* is automatically closed by auto_cfile's dtor when it goes out of scope.
No need of a "try ... catch" block at all, much less of "finally," which is an unnecessary addition in C#, IMHO.
<snip>
In a case as simple as FILE* I may agree with you. But sometimes I have to do something more complicated than fclose, and this something is not associated with any handle like FILE*. For example, I can express the code to be executed inevitably, even if an exception occurs at some point, as a scope guard. void foo() { // some code here... BOOST_SCOPE_GUARD_BEGIN(whatever) { // This code is executed even if the function below // throws. This function may be out of this module's // scope, so I generally don't know (and don't care) // wether it does throw or not, and if it does, what // it does throw. } BOOST_SCOPE_GUARD_END; bar(); } Another good use case for scope guards is making rollbackable code. But I see, this implementation doesn't support that. -- Best regards, Andrey mailto:andysem@mail.ru

Andrey Semashev wrote:
Another good use case for scope guards is making rollbackable code. But I see, this implementation doesn't support that.
bool rollback = true; // ... BOOST_SCOPE_EXIT( (rollback) ) { if(rollback) do_rollback(); } BOOST_SCOPE_EXIT_END // ... rollback = false; // commit -- Alexander Nasonov http://nasonov.blogspot.com What would men be without women? Scarce, sir, mighty scarce. -- Mark Twain -- 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

Hello Alexander, Monday, April 9, 2007, 10:46:24 AM, you wrote:
Andrey Semashev wrote:
Another good use case for scope guards is making rollbackable code. But I see, this implementation doesn't support that.
bool rollback = true; // ...
BOOST_SCOPE_EXIT( (rollback) ) { if(rollback) do_rollback(); } BOOST_SCOPE_EXIT_END
// ... rollback = false; // commit
Yes, that is possible. Obviously, I didn't express myself well. I meant, it doesn't have a special support for it. What I was thinking is somewhat like this: guard_stack transaction; for (int i = 0; i < n; ++i) { do_smth(i); transaction.push(bind(&undo_smth, i)); } transaction.commit(); IMHO, this looks a little more cute. -- Best regards, Andrey mailto:andysem@mail.ru

Hello Andrey. On 9-Apr-07, at 12:56 PM, Andrey Semashev wrote:
Hello Alexander,
Monday, April 9, 2007, 10:46:24 AM, you wrote:
Andrey Semashev wrote:
Another good use case for scope guards is making rollbackable code. But I see, this implementation doesn't support that.
bool rollback = true; // ...
BOOST_SCOPE_EXIT( (rollback) ) { if(rollback) do_rollback(); } BOOST_SCOPE_EXIT_END
// ... rollback = false; // commit
Yes, that is possible. Obviously, I didn't express myself well. I meant, it doesn't have a special support for it. What I was thinking is somewhat like this:
guard_stack transaction;
for (int i = 0; i < n; ++i) { do_smth(i); transaction.push(bind(&undo_smth, i)); }
transaction.commit();
IMHO, this looks a little more cute.
Although I admit such an addition to the library would be great, IMHO, this is outside the scope of the functionality planned here. Why not a Boost.Transaction library? What do you think? Hans
-- Best regards, Andrey mailto:andysem@mail.ru
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

Hello Hans, Thursday, April 12, 2007, 12:13:08 AM, you wrote:
Andrey Semashev wrote:
Another good use case for scope guards is making rollbackable code. But I see, this implementation doesn't support that.
bool rollback = true; // ...
BOOST_SCOPE_EXIT( (rollback) ) { if(rollback) do_rollback(); } BOOST_SCOPE_EXIT_END
// ... rollback = false; // commit
Yes, that is possible. Obviously, I didn't express myself well. I meant, it doesn't have a special support for it. What I was thinking is somewhat like this:
guard_stack transaction;
for (int i = 0; i < n; ++i) { do_smth(i); transaction.push(bind(&undo_smth, i)); }
transaction.commit();
IMHO, this looks a little more cute.
Although I admit such an addition to the library would be great, IMHO, this is outside the scope of the functionality planned here. Why not a Boost.Transaction library? What do you think?
Well, I have it implemented, though not documented except for doxygen and with no tests yet (although I have plenty real-world usages of it to be sure in its reliability to some degree). I name it as a scope guard library and it intersects in functionality with your proposal, which is the second reason I didn't propose it before. But if you are interested I can upload it into vault on the weekend (there are lots of national language comments that need to be translated :) ). -- Best regards, Andrey mailto:andysem@mail.ru

Gregory Dai wrote:
Well, I'm very late to this thread of discussion, but I'd like to add my $0.02.
Why would we go through so much complexity? Remember the simple and basic principle of RAII? In situations like this, you just make a simple wrapper of the FILE* ... Please read the tutorial starting from
First off, ScopeExit is recommended only if RAII doesn't fit well. For example, if you plan to call std::fclose from inside ScopeExit, you should probably replace pointers to std::FILE with fstream objects or write a wrapper for std::FILE. Lets assume you need to maintain an in memory database of Person objects: ... http://194.6.223.221/~nasonov/scope_exit-0.02/libs/scope_exit/doc/html
No need of a "try ... catch" block at all, much less of "finally," which is an unnecessary addition in C#, IMHO. ScopeExit doesn't need try-catch either.
-- Alexander Nasonov http://nasonov.blogspot.com Though I am not naturally honest, I am sometimes by chance. -- William Shakespeare -- 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 (8)
-
Alexander Nasonov
-
Andrey Semashev
-
Felipe Magno de Almeida
-
Gregory Dai
-
Hans Larsen
-
Martin Bonner
-
Shams
-
Steven Watanabe