Boost logo

Boost :

Subject: Re: [boost] Proposed new RAII Library
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2012-09-15 23:39:22


On Sat, Sep 15, 2012 at 10:55 AM, Lorenzo Caminiti
<lorcaminiti_at_[hidden]> wrote:
> As I said I could but only if it's about adding something as simple as
> the above scope_exit... I'm not sure if that's enough.

Here's how it could look like.

1) As of now you can use SCOPE_EXIT on both C++03 and C++11 to do the
following (macros :( ):

void close_handle(int& h) { std::cout << "closing: " << h << std::endl; h = 0; }

int main() {
    bool dismiss = false;

    int x = 1;
    BOOST_SCOPE_EXIT(&dismiss, &x) {
        if(!dismiss) close_handle(x);
    } BOOST_SCOPE_EXIT_END

    ...

2) If the following (non optimized) class where to be added to Scope Exit:

namespace boost { namespace scope_exit {

struct guard {
    template<typename Lambda>
    guard(Lambda f) : f_(f) {}
    ~guard() { f_(); }
private:
    boost::function<void ()> f_;
};

} } // namespace

It could be used on C++11 to do the following (no macros :) but C++11 only :( ):

    int y = 2;
    boost::scope_exit::guard exit_y = [&dismiss, &y] {
        if(!dismiss) close_handle(y);
    };

3) On C++03, if you were willing to write an extra close_handle_unless
function (no macros :) but extra function :( , if you use a local
function you are using macros again :( so option 1 is a better
option):

void close_handle_unless(bool const cond, int& h) { if(!cond) close_handle(h); }

    ....

    int z = 3;
    boost::scope_exit::guard exit_z = boost::bind(
            close_handle_unless, boost::ref(dismiss), boost::ref(z));

4) On C++03, if you were willing to use Phoenix (no macro :( but extra
Phoenix adapted function and Phoenix's syntax :( ):

BOOST_PHOENIX_ADAPT_FUNCTION(void, close_handle_, close_handle, 1)

    ...

    int w = 4;
    boost::scope_exit::guard exit_w =
        if_(!ref(dismiss)) [
            close_handle_(ref(w))
        ]
    ;

A complete example is attached.

Also note how in this case the same dismiss control variable is used
to dismiss all the scope exits--that's an argument to leave the
dismiss feature up to the user and outside RAII lib (as if each scope
exit guard had a dismiss data member, I would have to sync all of them
one-by-one increasing the probability of a bug) in addition to the
fact that in some cases there could be no need for the dismiss
functionality but the RAII patter would still apply (IMO, the RAII
patter and the dismiss functionality are separate things, they should
be linked only by the user when that makes sense for the user's
application logic).

Personally, I'd just use the Scope Exit macros if I need to write code
portable between C++03 and C++11 (option 1) and the (trivial) guard
class if I have to write code that can rely on C++11 lambdas (option
2).

HTH,
--Lorenzo




Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk