1

Making use of RAII requires to create a class to benefit from the mechanism that automatically calls the destructor of automatic variables when exiting a scope.

However, there are some cases when writing a new class in order to "release" something or unset something seems to be too much work.

For example, if you have a method that sets the value of a field only for the duration of the call, then you have to manually unset it if the call returns or throws, and it wouldn't be practical and intuitive to write a class that would just automatically unset that field and that would only be usable for this particular case.

So I thought about writing some kind of all-purpose class that can make use of RAII for all cases for which it is not really worth making a class.

The idea is that you provide an object instance, a method pointer to be called on construction, and a method pointer to be called on destruction :

template< class T >
class guard
{
private:

    T * const m_pInstance;

    void (T::* const m_fnInitialize)();

    void (T::* const m_fnFinalize)() throw();

public:

    guard( T * pInstance, void (T::* fnInitialize)(), void (T::* fnFinalize)() throw() ) :
        m_pInstance    ( pInstance    ),
        m_fnInitialize ( fnInitialize ),
        m_fnFinalize   ( fnFinalize   )
    {
        (m_pInstance->*m_fnInitialize)();
    }

    ~guard() throw()
    {
        (m_pInstance->*m_fnFinalize)();
    }
};

Which can the be used like this :

class some_class
{
private:

    int m_iField;

public:

    some_class() : m_iField( 0 )
    {
    }

    void set()
    {
        std::cout << "set()" << std::endl;
        m_iField = 1;
    }

    void unset() throw()
    {
        std::cout << "unset()" << std::endl;
        m_iField = 0;
    }
};

int main( int argc, char ** argv )
{
    some_class oObj;

    {
        core::guard< some_class > oGuard( & oObj, & some_class::set, & some_class::unset );
    }

    system( "pause" );

    return 0;
}

It seels to me like it could be handy. But do you see any reason why this would be a bad practice ?

Also the way I designed this is not entirely "generic" as it poses some constraints : the initialization and finalization methods are non-const and the finalization method may no throw. Are there ways to making this more flexible ?

Thank you.

Virus721
  • 8,061
  • 12
  • 67
  • 123
  • This is how [`std::lock_guard`](http://en.cppreference.com/w/cpp/thread/lock_guard) does it, it imposes some constraints, namely the template parameter class must provide `lock` and `unlock` methods. – Olaf Dietsche Dec 09 '16 at 10:58
  • I would like to provide freedom for the method names because an object might have more than one pair of methods. Like lock_member_1/unlock_member_1 and lock_member_2/unlock_member_2 on the same object. – Virus721 Dec 09 '16 at 11:00
  • 1
    You don't need to store `m_fnInitialize`, because it is only used in the constructor. – Olaf Dietsche Dec 09 '16 at 11:03
  • 1
    In addition to your "object and two method pointer" version, you might also look at a "two non-member function" version which could be used nicely with lambdas. – Allison Lock Dec 09 '16 at 11:04
  • Thanks for the comments. I forgot the mention that I can't use C++11, as the throw() suggests, but that's good to know. – Virus721 Dec 09 '16 at 11:11
  • 1
    There is some standardization work ongoing for generic scope guards, see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0052r2.pdf Sometimes, you can also use e.g. unique_ptr with custom deleter. – Erik Alapää Dec 09 '16 at 11:50
  • Related: http://stackoverflow.com/questions/7779652/try-catch-finally-construct-is-it-in-c11 – Joseph Ireland Dec 09 '16 at 11:52

0 Answers0