C++11 scope exit guard, a good idea?

前端 未结 10 798
囚心锁ツ
囚心锁ツ 2020-12-08 05:00

I\'ve written a small utility class for C++11 which I use as a scope guard for easier handling of exception safety and similar things.

Seems somewhat like a hack. Bu

相关标签:
10条回答
  • 2020-12-08 05:37

    The implementation could be very much simplified using tr1::function and tr1::unique_ptr, as below:

    namespace detail
    {
        class ScopeGuard
        {
        public:
            explicit ScopeGuard(std::function<void()> onExitScope) 
                : onExitScope_(onExitScope), dismissed_(false)
            { }
    
            ~ScopeGuard()
            {
                try
                {
                    if(!dismissed_)
                    {
                        onExitScope_();
                    }
                }
                catch(...){}
            }
    
            void Dismiss()
            {
                dismissed_ = true;
            }
        private:
            std::function<void()> onExitScope_;
            bool dismissed_;
    
            // noncopyable
        private:
            ScopeGuard(ScopeGuard const&);
            ScopeGuard& operator=(ScopeGuard const&);
        };
    }
    
    inline std::unique_ptr<detail::ScopeGuard> CreateScopeGuard(std::function<void()> onExitScope)
    {
        return std::unique_ptr<detail::ScopeGuard>(new detail::ScopeGuard(onExitScope));
    }
    
    0 讨论(0)
  • 2020-12-08 05:38

    But is it a good idea?

    Sure. A related topic is the RAII paradigm.

    Or are there potential problems I have missed?

    You don't handle exceptions.

    Is there already a similar solution (with C++0x features) in boost or similar?

    Alexandrescu came up with ScopeGuard a long time back. Both Boost and std::tr1 has a thing called scoped_ptr and shared_ptr (with a custom deleter) that allows you to accomplish just this.

    0 讨论(0)
  • 2020-12-08 05:39

    This is a good idea, but there are a couple of problems with you class.

    1. you should disable the new operator (you don't want to need the user to use it in such a way that forces to call delete on this, right?)
    2. you need a "commit" function, in order for this to be a scope guard instead of a simple RAII

    notice that if you implement point 2 you need a meaningful name for each scopeguard you instantiate. This is, in general, not a problem, but it could be in your application (or to your taste).

    Finally, this question would probably have been more appropriate for CodeReview.

    0 讨论(0)
  • 2020-12-08 05:42

    If replace create_scope_exit by a binary operator, we can remove parentheses:

    class at_scope_exit
    {
        template<typename F>
        struct scope_exit_fn_holder : boost::noncopyable
        {
            scope_exit_fn_holder(F&& f) : f(std::forward<F>(f)) {}
    
            F f;
            ~scope_exit_fn_holder() { f(); }
        };
    
        template<typename F>
        friend scope_exit_fn_holder<F> operator==(at_scope_exit, F&& f)
        {
            return scope_exit_fn_holder<F>(std::forward<F>(f));
        }
    };
    

    Usage:

    auto atScopeExit = at_scope_exit() == [&]
    {
        ...
    };
    

    upd:
    Corresponding macro:

    #include <boost/preprocessor/cat.hpp>
    
    #define AT_SCOPE_EXIT auto BOOST_PP_CAT(scopeExit_, __LINE__) = at_scope_exit() == [&]
    #define AT_SCOPE_EXIT_EX(...) auto BOOST_PP_CAT(scopeExit_, __LINE__) = at_scope_exit() == [__VA_ARGS__]
    
    0 讨论(0)
提交回复
热议问题