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

前端 未结 10 797
囚心锁ツ
囚心锁ツ 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:16

    Scope guards are definitely a good idea. I think the scope guard concept is potent tool for exception safety. If you can make a safer, cleaner version that Boost's ScopeExit using C++0x syntax, I think it would be well worth your time.

    Similar to Alexandrescu's ScopeGuard and Boost's ScopeExit , the D programming language has direct syntax for this sort of thing. The D programming team thought the scope guard was a good enough idea that they added it directly to the language (ie it's not implemented in a library).

    Example.

    void foo( bool fail )
    {
       scope(exit)
       {
          writeln("I'm always printed");
       }
    
       scope(success) writeln("The function exited normally");
    
       scope(error)
          writeln("The function exited with an exception.");
    
       if( fail )
          throw new Exception("Die Die Die!");
    }
    

    The scope based guards aren't anything new. It's functionality can easily be replicated with a class destructor (RAII and all that). It's also possible to replace with try/finally in C# or Java. Heck, even pthreads provides a rudimentary scope guard, called pthread_cleanup_push.

    What makes scope guards so powerful is when you have multiple scope(*) statements in the function. It scales incredibly well, as opposed to try/finally which require super human powers to manage anything more than two.

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

    Using Boost:

    #include <boost/preprocessor/cat.hpp>
    
    template<class Fn>
    class ScopeGuardDetails {
        const Fn m_fn;
    public:
        constexpr ScopeGuardDetails(Fn &&fn) : m_fn(fn) {}
        ~ScopeGuardDetails() { m_fn(); }
    };
    #define ScopeGuardName BOOST_PP_CAT(BOOST_PP_CAT(__scope_guard, _), BOOST_PP_CAT(BOOST_PP_CAT(__LINE__, _), __COUNTER__))
    #define defer(stmt) const auto ScopeGuardName = [](const auto _fn) { \
        return ScopeGuardDetails<decltype(_fn)> { std::move(_fn) }; \
    }([&] { stmt });
    

    Usage:

    if (gdiplus::GdiplusStartup(&token, &startupInput, nullptr) == Gdiplus::Ok) {
        defer({
            gdiplus::GdiplusShutdown(token);
        });
        ...
    }
    
    0 讨论(0)
  • 2020-12-08 05:20

    my $0.02

    struct at_scope_end
    {
        std::function < void () > Action;
    
        at_scope_end (std::function < void () > Action) :
            Action (Action)
        {
        }
    
        ~at_scope_end ()
        {
            Action ();
        }
    };
    
    #define AT_SCOPE_END_CAT(x,y)    x##y
    #define AT_SCOPE_END_ID(index)   AT_SCOPE_END_CAT(__sg, index)
    #define AT_SCOPE_END(expr)      at_scope_end AT_SCOPE_END_ID(__LINE__) ( [&] () { expr; } );
    
    0 讨论(0)
  • 2020-12-08 05:25

    For the record, there is scope_exit in the TS 3

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

    For the record, there is Boost ScopeExit.

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

    We could omit the ugly [&] stuff by putting it in the define:

    #define UTILITY_SCOPE_EXIT(f) const auto& _UTILITY_EXIT_SCOPE_LINENAME(EXIT, __LINE__) = ::detail::create_scope_exit([&]f)
    

    Then:

    UTILITY_SCOPE_EXIT({myfile.close();});
    

    Tested with MSVC++ 11.0 (VS2012). Regards.

    0 讨论(0)
提交回复
热议问题