|
Boost : |
Subject: Re: [boost] Proposed new RAII Library
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2012-09-14 16:08:49
Le 14/09/12 20:48, Sohail Somani a écrit :
> On 14/09/2012 2:37 PM, Alexander Nasonov wrote:
>> And then:
>>
>> bool dismiss = false;
>>
>> ...
>>
>> UNARY_SCOPE_EXIT(dismiss, CloseHandle, handle);
>>
>> ...
>>
>> dismiss = true;
>
> What. Are you really trying to make a case against:
>
> boost::scope_guard kanyewest(CloseHandle,handle);
>
> ...
> kanyewest.dismiss();
>
> Or in C++11:
>
> boost::scope_guard lolwhat( [&](){ CloseHandle(handle); } );
>
> ...
> lolwhat.dismiss();
>
Yes, I'm. Encapsulating the dismiss condition on the scope_guard doesn't
scale when you have several actions that need to be executed. Compare
bool dismiss = false;
...
UNARY_SCOPE_EXIT(dismiss, CloseHandle, handle1);
UNARY_SCOPE_EXIT(dismiss, CloseHandle, handle2);
...
dismiss = true;
with
boost::scope_guard lolwhat1( [&](){ CloseHandle(handle1); } );
boost::scope_guard lolwhat2( [&](){ CloseHandle(handle2); } );
...
lolwhat1.dismiss();
lolwhat2.dismiss();
Not only you need to dismiss twice, but you need to name differently
your scope guards and don't forget to dismiss all of them.
> Macros are magic and I concur with the other poster that unless the
> magic cannot be avoided, don't rely on it.
You are right. Macros should be avoided when possible. The interface of
your class should be modified to take care of an external dismiss condition.
bool dismiss = false;
...
boost::dismissed_scope_guard lolwhat1(dismiss, [&](){
CloseHandle(handle1); } );
boost::dismissed_scope_guard lolwhat2(dismiss, [&](){
CloseHandle(handle2); } );
...
dismiss = true;
Or passing it to the ClocseHandle function
bool dismiss = false;
...
boost::scope_guard lolwhat1( [&](){
CloseHandleIfNot(dismiss,handle1); } );
boost::scope_guard lolwhat2( [&](){
CloseHandleIfNot(dismiss,handle2); } );
...
dismiss = true;
or to the lambda
bool dismiss = false;
...
boost::scope_guard lolwhat1( [&](){ if (!dismiss)
CloseHandle(handle1); } );
boost::scope_guard lolwhat2( [&](){ if (!dismiss)
CloseHandle(handle2); } );
...
dismiss = true;
which I prefer, as in this case, scope_guard doesn't provide unnecessary
behavior and I don't need to define an new function that takes care of
the dismiss condition.
In addition, the problem is that sometimes the dismiss condition is not
stored in a variable, so that mandating the use of one is not desired.
> I'm not sure why this is so hard. People who use this pattern find it
> more useful that BOOST_SCOPE_EXIT. People who don't, don't. Film at 11.
>
While this non-macro interface is possible only with C++11 lambdas,
there is no portable way to do it (as generic as the last usage) in C++03.
We need the pre-processor to have the same functionality, and this was
the motivation of Boost.ScopeExit.
So resuming, the boost::scope_guard (without a dismiss state) is a
convenient abstraction for c++11 compilers supporting lambdas, and
Boost.ScopeExit reflects the same abstraction for C++03.
I will be for an extension of Boost.ScopeExit that provides a non-macro
interface, like the one of the preceding scope_guard, for the people
that don't need to make their code portable to non c++11 compilers. I
will name it however scoped_exit.
Extracted from the Boost.ScopeExit
struct scope_exit {
scope_exit(std::function<void (void)> f) : f_(f) {}
~scope_exit(void) { f_(); }
private:
std::function<void (void)> f_;
};
bool dismiss = false;
...
boost::scope_exit lolwhat1( [&](){ if (!dismiss)
CloseHandle(handle1); } );
boost::scope_exit lolwhat2( [&](){ if (!dismiss)
CloseHandle(handle2); } );
...
dismiss = true;
I don't know if I will use in my code the proposed scope_guard interface
having as parameters a function and its arguments, as in
boost::scope_guard kanyewest(CloseHandleIfNot, dismiss, handle);
Best,
Vicente
P.S.. The lambdas are missing some parameters, as dismiss, handle, ...
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk