
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, ...