RAII for value objects

Discussion in 'C++' started by Markus Elfring, Nov 10, 2004.

  1. The class "auto_ptr" implements the RAII pattern for pointer types. It
    seems that an implementation is not provided for non-pointer values by
    the STL so far.
    I imagine to use the "acquisition" for boolean values or flags.

    Would you like that a template class will be added to implement locks
    or state indicators for example?

    Regards,
    Markus
    Markus Elfring, Nov 10, 2004
    #1
    1. Advertising

  2. Markus Elfring

    Buster Guest

    Markus Elfring wrote:
    > The class "auto_ptr" implements the RAII pattern for pointer types. It
    > seems that an implementation is not provided for non-pointer values by
    > the STL so far.
    > I imagine to use the "acquisition" for boolean values or flags.
    >
    > Would you like that a template class will be added to implement locks
    > or state indicators for example?


    RAII is supported directly by the language. Write a class with a
    constructor and a destructor, having a data member of the value type you
    require.
    Buster, Nov 11, 2004
    #2
    1. Advertising

  3. "Markus Elfring" wrote:

    > The class "auto_ptr" implements the RAII pattern for pointer types. It
    > seems that an implementation is not provided for non-pointer values by
    > the STL so far.
    > I imagine to use the "acquisition" for boolean values or flags.
    >

    Take look on state_saver class inside Boost.Serialization library
    version 1.32 (available on http://www.boost.org/ as pre-release,
    will be released really soon now).

    /Pavel
    Pavel Vozenilek, Nov 11, 2004
    #3
  4. > Take look on state_saver class inside Boost.Serialization library
    > version 1.32 (available on http://www.boost.org/ as pre-release,
    > will be released really soon now).


    The implementation that is described in the document
    "http://boost.org/libs/io/doc/ios_state.html" is too much for the use
    cases that I suggested.
    It is great for the intended application area. Would you like to
    extract the core RAII from your approach to show an efficient boost
    style solution?

    Regards,
    Markus
    Markus Elfring, Nov 12, 2004
    #4
  5. > RAII is supported directly by the language. Write a class with a
    > constructor and a destructor, having a data member of the value type you
    > require.


    How do you think about this design sketch?

    template<typename X, const initial, const final>
    class RAII
    {
    public:
    RAII() : _value(initial) {}
    RAII(const X& x) : _value(x) {}
    ~RAII () { _value = final; }

    X& operator=(const X& x) { if (this != &x) { _value = x._value }
    return *this; }
    X& operator*() const { return _value; }
    X* operator->() const throw() { return &_value; }
    // Do you need more methods?

    private:
    X _value;
    }

    I imagine also a variant that performs method calls (lock / unlock for
    example) instead of the assignments in the constructor and destructor.
    The constant template parameters must be replaced by an other useful
    type in this case.

    Regards,
    Markus
    Markus Elfring, Nov 12, 2004
    #5
  6. Markus Elfring

    Buster Guest

    Markus Elfring wrote:
    >>RAII is supported directly by the language. Write a class with a
    >>constructor and a destructor, having a data member of the value type you
    >>require.

    >
    >
    > How do you think about this design sketch?
    >
    > template<typename X, const initial, const final>
    > class RAII
    > {
    > public:
    > RAII() : _value(initial) {}
    > RAII(const X& x) : _value(x) {}
    > ~RAII () { _value = final; }
    >
    > X& operator=(const X& x) { if (this != &x) { _value = x._value }
    > return *this; }
    > X& operator*() const { return _value; }
    > X* operator->() const throw() { return &_value; }
    > // Do you need more methods?
    >
    > private:
    > X _value;
    > }


    I don't like it. The type you want is "T", not "RAII <T>".

    > I imagine also a variant that performs method calls (lock / unlock for
    > example) instead of the assignments in the constructor and destructor.
    > The constant template parameters must be replaced by an other useful
    > type in this case.
    Buster, Nov 13, 2004
    #6
  7. Markus Elfring, Nov 13, 2004
    #7
  8. > I imagine also a variant that performs method calls (lock / unlock for
    > example) instead of the assignments in the constructor and destructor.
    > The constant template parameters must be replaced by an other useful
    > type in this case.


    How do you think about the following design alternatives?

    class method_pair
    {
    public:
    method_pair() {}
    virtual ~method_pair() {}

    virtual void begin() = 0;
    virtual void end() = 0;
    }

    template<class MP> class RAII2
    {
    public:
    RAII2(MP& mp) : _m_p(mp) { _m_p.begin(); }
    ~RAII2() { _m_p.end(); }

    // Is anything missing here?

    private:
    MP& _m_p;
    }

    template<class MP> class RAII3 : private MP
    {
    public:
    RAII3() { begin(); }
    ~RAII3() { end(); }

    // Is anything missing here?
    }

    I guess that the implementations will need a few more typedefs and
    reformatting to fulfill the requirements and conventions of good
    libraries.
    Would this proposal be an acceptable candidate for addition to the
    standard templates library?

    Regards,
    Markus
    Markus Elfring, Nov 13, 2004
    #8
  9. "Markus Elfring" wrote:

    > > Take look on state_saver class inside Boost.Serialization library
    > > version 1.32 (available on http://www.boost.org/ as pre-release,
    > > will be released really soon now).

    >
    > The implementation that is described in the document
    > "http://boost.org/libs/io/doc/ios_state.html" is too much for the use
    > cases that I suggested.
    > It is great for the intended application area. Would you like to
    > extract the core RAII from your approach to show an efficient boost
    > style solution?
    >

    There are plans to convert state_saver into independent
    Boost lib though AFAIK it didn't started yet.

    /Pavel
    Pavel Vozenilek, Nov 13, 2004
    #9
  10. Markus Elfring

    Buster Guest

    Buster, Nov 13, 2004
    #10
  11. Markus Elfring

    Buster Guest

    Markus Elfring wrote:

    >>I imagine also a variant that performs method calls (lock / unlock for
    >>example) instead of the assignments in the constructor and destructor.
    >>The constant template parameters must be replaced by an other useful
    >>type in this case.

    >
    >
    > How do you think about the following design alternatives?
    >
    > class method_pair
    > {
    > public:
    > method_pair() {}
    > virtual ~method_pair() {}
    >
    > virtual void begin() = 0;
    > virtual void end() = 0;
    > }
    >
    > template<class MP> class RAII2
    > {
    > public:
    > RAII2(MP& mp) : _m_p(mp) { _m_p.begin(); }
    > ~RAII2() { _m_p.end(); }
    >
    > // Is anything missing here?
    >
    > private:
    > MP& _m_p;
    > }
    >
    > template<class MP> class RAII3 : private MP
    > {
    > public:
    > RAII3() { begin(); }
    > ~RAII3() { end(); }
    >
    > // Is anything missing here?
    > }
    >
    > I guess that the implementations will need a few more typedefs and
    > reformatting to fulfill the requirements and conventions of good
    > libraries.
    > Would this proposal be an acceptable candidate for addition to the
    > standard templates library?


    No, I still don't like it. Perhaps an example will help. Say you have a
    class, X, with a constructor and destructor. Then using your RAII2
    class, for example, you might need this much code:

    class X_MP_adapter : public method_pair
    {
    public:
    void begin () { x = new X; }
    void end () { delete x; }
    private:
    X x;
    };

    void function ()
    {
    RAII2 <MP_adapter> x;
    // Do some stuff.
    // Finalization code called automatically.
    }

    This seems like a waste of time. First of all, the base class
    method_pair and its virtual functions are unnecessary because, in virtue
    of the template parameter MP, you know what the static type of
    RAII2::_m_p is (in this case, X_MP_adapter) is. You just need to
    document in RAII2 that the statements "x.begin ();" and "x.end ();" must
    be well formed for an object x of type MP.

    More to the point, you don't need the X_MP_adapter and RAII2 classes at
    all. You can just write:

    void function ()
    {
    X x;
    // Do some stuff.
    // Finalization code called automatically.
    }

    Is there some specific problem you're trying to solve? If I've missed
    your point, it might help me to understand better if I saw some real
    code.

    --
    Regards,
    Buster
    Buster, Nov 13, 2004
    #11
  12. > No, I still don't like it. Perhaps an example will help.

    How do you think about a design with function objects?

    template<typename Context> class initializer
    : public unary_function<Context, void>
    {
    initializer() {}
    virtual ~initializer() {}

    virtual void operator() (argument_type& context) = 0;
    }

    template<typename Context> class finalizer
    : public unary_function<Context, void>
    {
    finalizer() {}
    virtual ~finalizer() {}

    virtual void operator() (argument_type& context) = 0;
    }

    // Does it make sense to introduce an interface "Callable"?

    template<typename Context,
    template<typename Context> class initializer,
    template<typename Context> class finalizer>
    class RAII4
    : private initializer<Context>, finalizer<Context>
    {
    public:
    RAII4(Context& c) : _context(c) {}
    virtual ~RAII4() {}

    virtual void begin() { initializer<Context>::eek:perator()(_context); };
    virtual void end() { finalizer<Context>::eek:perator()(_context); };

    // Would you like to add anything here?

    private:
    Context& _context;
    }


    // small example: templates and classes in action

    class door : public method_pair
    {
    public:
    door() {}
    virtual ~door() {}

    virtual void open() { cout << "Hallo"; };
    virtual void close() { cout << "Bye"; };

    virtual void begin() { open(); };
    virtual void end() { close(); };
    }

    class room : public method_pair
    {
    public:
    method_pair() : _guard(_one) {}
    virtual ~method_pair() {}

    virtual void enter() { _one.open(); cout << "Nice furniture"; };
    virtual void leave() { cout << "See you later"; _one.close(); };

    virtual void begin() { enter(); };
    virtual void end() { leave(); };

    private:
    door _one;
    RAII2<door> _guard;
    }

    Regards,
    Markus
    Markus Elfring, Nov 14, 2004
    #12
  13. > I'm sorry, I don't understand the question.

    I think that you can ignore the type change because you want to
    achieve that a variable will be initalized once and the cleanup will
    be automatically performed when its scope has ended.

    I hope that a compiler does not optimize the resulting instructions
    away because it might happen that no of its other methods will be
    directly called after its initialization (=> unused variable?).
    That is the usual precondition for the successful work of the RAII
    idiom.

    Regards,
    Markus
    Markus Elfring, Nov 14, 2004
    #13
  14. > There are plans to convert state_saver into independent
    > Boost lib though AFAIK it didn't started yet.


    Is your development different from the "IO stream state savers"?
    Are you planning to create separate components?
    Markus Elfring, Nov 14, 2004
    #14
  15. Markus Elfring, Nov 14, 2004
    #15
  16. > This seems like a waste of time. First of all, the base class
    > method_pair and its virtual functions are unnecessary because, in virtue
    > of the template parameter MP, you know what the static type of
    > RAII2::_m_p is (in this case, X_MP_adapter) is. You just need to
    > document in RAII2 that the statements "x.begin ();" and "x.end ();" must
    > be well formed for an object x of type MP.


    I try to express the RAII design pattern/idiom in C++ language terms.

    I think that the virtual methods are needed so that they can be
    overloaded.
    Do you know a wording which would achieve a similar effect with code
    generation by the templates?

    The difference between RAII2 and RAII3 is this:
    - RAII2 uses delegation over the variable "_m_p". A method pair can be
    selected at run time.
    - RAII3 uses private inheritance to specify construction and
    destruction as an implementation detail that should not be visible to
    the clients of the class. The selction is done at compile time.


    > More to the point, you don't need the X_MP_adapter and RAII2 classes at
    > all. You can just write:
    >
    > void function ()
    > {
    > X x;
    > // Do some stuff.
    > // Finalization code called automatically.
    > }


    The adapter or wrapper is needed if your class X offers two related
    methods (a specific pair) to which calls should be encapsulated by the
    RAII technique.
    The methods "begin" and "end" should be kept private as far as
    possible because they play their role as a virtual constructor and
    destructor.

    Your "X_MP_adapter" sketch looks like an approach that is covered by
    the class "std::auto_ptr" already.
    I am interested in the RAII handling of data structures that are not
    concerned with a managed pointer.


    > Is there some specific problem you're trying to solve? If I've missed
    > your point, it might help me to understand better if I saw some real
    > code.


    Would you like to look at an other specific implementation?
    - http://zthread.sourceforge.net/html/classZThread_1_1Guard.html
    - http://zthread.sourceforge.net/html/classZThread_1_1LockedScope.html

    I see also use cases besides synchronization in the document "Memory
    model for multithreaded C++".
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1680.pdf

    I would like to use the class "std::atomic_int" with my suggestion.
    Such an integer value will be reset (e.g. 0 as default) in the
    destructor.
    I guess that the class "std::msync" will become another interesting
    candidate for some applications.

    Regards,
    Markus
    Markus Elfring, Nov 14, 2004
    #16
  17. "Pavel Vozenilek" <> wrote in message
    news:...

    > There are plans to convert state_saver into independent
    > Boost lib though AFAIK it didn't started yet.


    I remember Robert Ramey mentioning this, but I don't remember if Daryle Walker
    responded. Would this library supplant ios_state.hpp? This would be nice for me,
    since the io directory would then be empty ;-)

    Jonathan
    Jonathan Turkanis, Nov 14, 2004
    #17
  18. "Jonathan Turkanis" wrote:

    > > There are plans to convert state_saver into independent
    > > Boost lib though AFAIK it didn't started yet.

    >
    > I remember Robert Ramey mentioning this, but I don't remember if Daryle

    Walker
    > responded. Would this library supplant ios_state.hpp? This would be nice

    for me,
    > since the io directory would then be empty ;-)
    >

    It is looking for volunteer to make it standalone.
    Unsolved problem if what if operator= throws
    inside destructor.

    /Pavel
    Pavel Vozenilek, Nov 14, 2004
    #18
  19. Markus Elfring

    Buster Guest

    Markus Elfring wrote:
    >>I'm sorry, I don't understand the question.

    >
    >
    > I think that you can ignore the type change because you want to
    > achieve that a variable will be initalized once and the cleanup will
    > be automatically performed when its scope has ended.


    Guaranteed (modulo 'as-if').

    > I hope that a compiler does not optimize the resulting instructions
    > away because it might happen that no of its other methods will be
    > directly called after its initialization (=> unused variable?).


    That wouldn't be an optimization. That would be smashing your program
    with a sledgehammer.

    > That is the usual precondition for the successful work of the RAII
    > idiom.
    Buster, Nov 15, 2004
    #19
  20. Markus Elfring

    Buster Guest

    Markus Elfring wrote:

    >>This seems like a waste of time. First of all, the base class
    >>method_pair and its virtual functions are unnecessary because, in virtue
    >>of the template parameter MP, you know what the static type of
    >>RAII2::_m_p is (in this case, X_MP_adapter) is. You just need to
    >>document in RAII2 that the statements "x.begin ();" and "x.end ();" must
    >>be well formed for an object x of type MP.

    >
    >
    > I try to express the RAII design pattern/idiom in C++ language terms.
    >
    > I think that the virtual methods are needed so that they can be
    > overloaded.


    "Overridden". You're right, I think, but a real example would help to
    convince me. I can't think of a situation where you know at compile time
    that there needs to be some RAII done, but you don't know exactly what
    the resource is going to be until run time. Enlighten me?

    > Do you know a wording which would achieve a similar effect with code
    > generation by the templates?


    Sure. Check out the standard C++ library algorithms. Here's a simple
    example. Notice there's no code at all corresponding to the Concept.

    // Concept: Transmogrifiable.
    // If x is an object of a type T which models
    // the Transmogrifiable concept, then the
    // following expression is valid:
    //
    // x.transmogrify ();
    // Postcondition: x is transmogrified.

    // Algorithm: transmogrify_n
    // If x is an object of a type T which models
    // the Transmogrifiable concept, and n is an integer,
    // then the following expression is valid:
    //
    // transmogrify_n (x, n);
    // Postcondition: x is transmogrified n times.

    template <typename T, typename Integer>
    void transmogrify_n (T & x, Integer n)
    {
    for (Integer i (0); i < n; ++ i)
    {
    x.transmogrify ();
    }
    }

    > The difference between RAII2 and RAII3 is this:
    > - RAII2 uses delegation over the variable "_m_p". A method pair can be
    > selected at run time.
    > - RAII3 uses private inheritance to specify construction and
    > destruction as an implementation detail that should not be visible to
    > the clients of the class. The selction is done at compile time.
    >
    >>More to the point, you don't need the X_MP_adapter and RAII2 classes at
    >>all. You can just write:
    >>
    >>void function ()
    >>{
    >> X x;
    >> // Do some stuff.
    >> // Finalization code called automatically.
    >>}

    >
    >
    > The adapter or wrapper is needed if your class X offers two related
    > methods (a specific pair) to which calls should be encapsulated by the
    > RAII technique.


    Sure. But why not use the constructor and destructor?

    > The methods "begin" and "end" should be kept private as far as
    > possible because they play their role as a virtual constructor and
    > destructor.


    Ah-hah. I suppose so.

    > Your "X_MP_adapter" sketch looks like an approach that is covered by
    > the class "std::auto_ptr" already.
    > I am interested in the RAII handling of data structures that are not
    > concerned with a managed pointer.
    >
    >>Is there some specific problem you're trying to solve? If I've missed
    >>your point, it might help me to understand better if I saw some real
    >>code.

    >
    >
    > Would you like to look at an other specific implementation?
    > - http://zthread.sourceforge.net/html/classZThread_1_1Guard.html
    > - http://zthread.sourceforge.net/html/classZThread_1_1LockedScope.html
    >
    > I see also use cases besides synchronization in the document "Memory
    > model for multithreaded C++".
    > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1680.pdf
    >
    > I would like to use the class "std::atomic_int" with my suggestion.
    > Such an integer value will be reset (e.g. 0 as default) in the
    > destructor.
    > I guess that the class "std::msync" will become another interesting
    > candidate for some applications.


    If it works, go for it. I think you're wasting your time trying to solve
    a very general problem, when the solution is easy (write a class with a
    constructor and destructor) for any particular instance of the problem.
    Buster, Nov 15, 2004
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. MikeB
    Replies:
    4
    Views:
    337
    Owen Jacobson
    Oct 26, 2004
  2. Replies:
    6
    Views:
    332
    Roland Pibinger
    Oct 10, 2006
  3. Johannes Schaub (litb)

    Re: Why is RAII called RAII?

    Johannes Schaub (litb), Sep 12, 2010, in forum: C++
    Replies:
    2
    Views:
    386
    James Kanze
    Sep 18, 2010
  4. cpp4ever

    Re: Why is RAII called RAII?

    cpp4ever, Sep 12, 2010, in forum: C++
    Replies:
    1
    Views:
    393
    BGB / cr88192
    Sep 13, 2010
  5. Goran Pusic

    Re: Why is RAII called RAII?

    Goran Pusic, Sep 13, 2010, in forum: C++
    Replies:
    11
    Views:
    532
    ptyxs
    Sep 16, 2010
Loading...

Share This Page