Pizer’s Weblog

programming, DSP, math

scope guards revisited [C++0x style]

with 7 comments

If you havn’t heard about scope guards you might want to have a look at this ddj article. The idea of scope guards is to provide a convenient tool for resource management when exception safety is an issue. Of course you can always try to write little special-purpose classes and create instances on the stack so that some specific (“cleanup”) action is performed in the destructor. Sometimes it’s just tedious to have to write those special classes and you wish for a tool that lets you get away without them. That’s a situation where the scope guard idiom could help you.

If you take a closer look at the scope guard implementation shown in that article you’ll see that there are basically three scope guard versions: one taking just a plain function object, another that takes a function object and some parameter (to be used with the function object) and a third one that’s able to call some object’s member function.

Also, you might have noticed that the flag ‘dismissed’ is declared mutable. This is sort of a little hack to emulate move semantics for the scope guard object. Why do we need this? Well, the utility function make_guard returns the scope guard object by value which means the object must be copyable. Your compiler probably optimizes any copy away in this case but still you need to have that object copyable in good old C++98. But a copy is not really what we want. If the object was simply copied we’d have two “active” instances. Both will invoke the function upon destruction. To avoid this, the “copy” in this design is destructive. It deactivates the source object.

In the the upcoming C++ standard (currently dubbed C++0x) we have new language features at our disposal that eases the sope guard’s implementation and use. The “mutable flag” hack to get move semantics is no longer necessary. Also, with having lambda expressions availble we only need to have the scope guard work with a function object that doesn’t take any parameters.

The following code compiles under g++ version 4.3.2 after enabling rvalue references (&&) via the -std=c++0x option:


/*  This demo compiles with g++ version 4.3.2:
 *  g++ -std=c++0x -o sg sg.cpp
 *
 *  rvalue references and lambdas are going to make
 *  the scope guard idiom simpler to implement & use.
 */

//----------[ "library magic" ... ]----------

#include <utility> // std::move

class scope_guard_base
{
   scope_guard_base& operator=(scope_guard_base const&);
protected:
   explicit scope_guard_base(bool a = true) : active(a) {}
   ~scope_guard_base() {}
   bool active;
public:
   void dismiss() { active = false; }
};

template<typename F>
class scope_guard_with_functor : public scope_guard_base
{
   F func;
   scope_guard_with_functor(scope_guard_with_functor const&);
   scope_guard_with_functor& operator=(scope_guard_with_functor const&);
public:
   explicit scope_guard_with_functor(F f)
      : func(std::move(f)) {}
   scope_guard_with_functor(scope_guard_with_functor && sg)
      : scope_guard_base(sg.active),
        func(std::move(sg.func)) { sg.active = false; }
   ~scope_guard_with_functor() { if (active) func(); }
};

template<typename F>
inline scope_guard_with_functor<F> make_guard(F f)
{ return scope_guard_with_functor<F>(std::move(f)); }

typedef scope_guard_base && scope_guard;

//----------[ demo ... ]----------

#include<iostream>

void replace_me_with_lambda()
{
   std::cout << "Bye World!" << std::endl;
}

int main()
{
   scope_guard sg = make_guard(replace_me_with_lambda);
   std::cout << "Hello World!" << std::endl;
   // sg.dismiss();
}


If you found a bug, tell me! :)

A lambda expression can now take care of various of actions you want to have performed right before the scope is left. But try to avoid throwing exceptions in these “cleanup” functions because the function is invoked in the scope guard’s destructor. It’s probably as bad as throwing an exception in a finally clause (Java) or worse. ;-)

As far as I know there exists an experimental C++ compiler that implemented lambda expressions. But I havn’t tried it (it may not even be available). So, I can’t guarantee that the following example is bugfree:


double* silly_idea_of_a_function()
{
   double* p = new double[123];
   scope_guard sg4p = make_guard( [p]{delete[] p;} );
   calculate_some_numbers(p); // might throw exception
   sg4p.dismiss();
   return p;
}


In the above example [p]{delete[] p;} is the lambda expression that makes the compiler create an instance of an anonymous class with a non-static const member function “operator()”. The code in the curly brackets will be the implementation of this member function. The square brackets right infront of it is the “lambda introducer”. It contains the capture clause (closure). In this case the pointer ‘p’ is captured by value. If you’re interested in the exact syntax and semantics you can check out the current specification draft N2798.pdf.

Of course this was just an example. In this particular instance you should handle resource management differently. Make it at least something like this:


unique_ptr<double[]> slightly_better()
{
   unique_ptr<double[]> p ( new double[123] );
   calculate_some_numbers(p.get()); // might throw exception
   return p;
}


It comes with the benefit of the function’s declaration being self-explanatory with respect to the resource’s life-time management. Still, you should favour standard containers that know their size. In C++0x they will become “movable” so you can easily return a local vector by value from a function without having to worry about whether the vector’s elements are copied or not. In C++98 compilers are allowed to elide copies in some situations and most compilers actually do. But there’s no guarantee. So, having movable types is a big plus in C++0x.

- P

About these ads

Written by pizer

November 22, 2008 at 3:42 pm

7 Responses

Subscribe to comments with RSS.

  1. specially with scope guards, I would really love to do the following (not current c++0x)

    template
    struct raii_handle {
    //…
    ~raii_handle( )
    {
    CLEANER(value);
    }

    T value;
    };

    with “auto” in the template parameter list accepting a non-type:

    raii_handle r2(malloced_int_pointer);

    so I no longer need to parametrize the struct using the type of the function and then sending the function pointer of std::free as a parameter (and storing it as part of the struct).

    The same efficiency in time and space as if I were using an empty function object and I was also applying empty base class optimization, but that worked as-is with standalone functions.

    Dark

    December 8, 2008 at 10:00 pm

  2. this thing ate my brackets! :(

    template[typename T, auto CLEANER]
    struct raii_handle {
    //…
    ~raii_handle( ) { CLEANER(value); }

    T value;
    };

    raii_handle r2[int*, std::free](malloced_int_pointer);

    Dark

    December 8, 2008 at 10:03 pm

  3. Hi, Dark!

    Check out std::unique_ptr. It allows using user-defined “deleters” which is similar to what you suggested. This class template will be part of the next C++ standard library.

    pizer

    December 8, 2008 at 10:27 pm

  4. Hey Pizer!

    Yeah I knew about the excellent std::unique_ptr class and its way too similar to what I want.

    However, the DELETER template-parameter of std::unique_ptr is a typename. To achieve zero overhead in time and space, we know we can do something like this

    struct malloc_deleter {
    void operator()(void* p)
    {
    std::free(p);
    }
    };

    unique_ptr[void*, malloc_deleter] p;
    // or a use of a lambda? haven’t checked those yet!

    and trust that the implementation optimizes for empty classes. This is of course expected, but what I wanted was merely syntactically simpler:

    raii_handle[void*, std::free] h;

    which would require to accept a non-type the deleter AND deducing its type. The current solution to what I wanted is the super hyper mega ugly:

    template[typename T, typename DELETER, DELETER D]
    struct raii_handle {
    // no need to store DELETER D, its a template
    // parameter
    };

    raii_handle[void*, void(*)(void*), std::free] h;
    // void(*)(void*) is redundant!, could be deduced

    My wish wouldn’t allow to have an stateful deleter as its currently possible in std::unique_ptr (and because of that, std::unique_ptr is way more useful). But it looks nicer when using simple C functions as deleters (most API’s fall under this category).

    Somewhere I read that for the next C++ standard (the one after C++0x) constexpr classes could be used as non-type template parameters (instead of only integral types). That would be way too cool and useful.

    Dark

    December 9, 2008 at 4:06 am

  5. It is already possible in C++98 to use references and pointers to variables and functions as template parameters as long as they have external linkage:

    template < typename T, void (&D)(T) >
    class raii {
    T x;
    private:
    // ... implementation ...
    ~raii() { D(x); }
    };

    typedef raii<int*, std::free> foo;

    I havn’t tested this piece of code. But you get the idea.

    Anyhow I’d still go with the deleter functor because there won’t be any runtime overhead involved provided that the compiler honors inline for member function declarations.

    pizer

    December 9, 2008 at 12:39 pm

  6. yes I know, but!

    template[typename T, void (&D)(T)]
    class raii;

    what if the function doesn’t return void? (for whatever reason). Also, if your function takes a T& or a const T&, then a simple T won’t match. That was my point. Deducing the type of a non-type parameter should be trivial, exactly like auto of C++0x.

    In one of the iterations of the auto proposal, the authors said they were studying the feasibility of exactly that:

    template[auto V] // non-type parameter, type deduced
    void f( )
    {
    // uses V
    decltype(V) another_v; // we can query its type
    }

    But since proposals tend to be as small as possible (and because this won’t open too many useful uses until constexpr objects are allowed as non-type template parameters), I think this was postponed.

    Nice blog :) one of the best I have seen.

    Dark

    December 9, 2008 at 3:33 pm

  7. Thank you! :) The template<auto …> thingy is a neat idea. I havn’t thought about that. But Function objects & inlined member functions should do the trick in terms of runtime efficienty at least. Some space may be wasted though even if your functor doesn’t have any member variables because sizeof(YourFunctor) must be greater than 0. But I think you could try private inheritence as alternative to a deleter member for your raii class. A good compiler “optimizes empty super classes away” I believe:

    template <typename T, typename D>
    class raii : private D {
    T x_;
    public:
    explicit raii(T x) : x_(move(x)) {}
    raii(T x, D d) : D(move(d)), x_(move(x)) {}
    ~raii() { (*this)(x_); } // superclass D provides operator()
    };

    pizer

    December 9, 2008 at 6:27 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: