tags:

views:

184

answers:

3

I've written a small utility class for C++0x which i use as a scope guard for easier handling exception safety and similar.

Seems somewhat like a hack. But I'm suprised i haven't seen it somewhere else using C++0x features. I think boost has something similar for C++98.

But is it a good idea? Or are there potential problems I have missed? Is there already a similar solution (with C++0x features) in boost or similar?

    namespace detail 
    {
        template<typename T>
        class scope_exit : boost::noncopyable
        {
        public:         
            explicit scope_exit(T&& exitScope) : exitScope_(std::forward<T>(exitScope)){}
            ~scope_exit(){try{exitScope_();}catch(...){}}
        private:
            T exitScope_;
        };          

        template <typename T>
        scope_exit<T> create_scope_exit(T&& exitScope)
        {
            return scope_exit<T>(std::forward<T>(exitScope));
        }
    }


#define _UTILITY_EXIT_SCOPE_LINENAME_CAT(name, line) name##line
#define _UTILITY_EXIT_SCOPE_LINENAME(name, line) _UTILITY_EXIT_SCOPE_LINENAME_CAT(name, line)
#define UTILITY_SCOPE_EXIT(f) const auto& _UTILITY_EXIT_SCOPE_LINENAME(EXIT, __LINE__) = ::detail::create_scope_exit(f)

and it's used something like.

int main () 
{
  ofstream myfile;
  myfile.open ("example.txt");
  UTILITY_SCOPE_EXIT([&]{myfile.close();}); // Make sure to close file even in case of exception
  myfile << "Writing this to a file.\n"; // Imagine this could throw
  return 0;
}
+7  A: 

But is it a good idea?

Sure. A related topic is the RAII paradigm.

Or are there potential problems I have missed?

You don't handle exceptions.

Is there already a similar solution (with C++0x features) in boost or similar?

Alexandrescu came up with ScopeGuard a long time back. Both Boost and std::tr1 has a thing called scoped_ptr and shared_ptr (with a custom deleter) that allows you to accomplish just this.

dirkgently
Where do I not handle exceptions? EDIT: Ofc the destructor.
ronag
Btw, scoped_ptr wasn't added to tr1 I believe?
ronag
It wasn't. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
Potatoswatter
Updated. I had missed `shared_ptr` stuff.
dirkgently
+2  A: 

For the record, there is Boost ScopeExit.

Gregory Pakosz
A: 

Scope guards are definitely a good idea. I think the scope guard concept is potent tool for exception safety. If you can make a safer, cleaner version that Boost's ScopeExit using C++0x syntax, I think it would be well worth your time.

Similar to Alexandrescu's ScopeGuard and Boost's ScopeExit , the D programming language has direct syntax for this sort of thing. The D programming team thought the scope guard was a good enough idea that they added it directly to the language (ie it's not implemented in a library).

Example.

void foo( bool fail )
{
   scope(exit)
   {
      writeln("I'm always printed");
   }

   scope(success) writeln("The function exited normally");

   scope(error)
      writeln("The function exited with an exception.");

   if( fail )
      throw new Exception("Die Die Die!");
}

The scope based guards aren't anything new. It's functionality can easily be replicated with a class destructor (RAII and all that). It's also possible to replace with try/finally in C# or Java. Heck, even pthreads provides a rudimentary scope guard, called pthread_cleanup_push.

What makes scope guards so powerful is when you have multiple scope(*) statements in the function. It scales incredibly well, as opposed to try/finally which require super human powers to manage anything more than two.

caspin