Call a function before function exits

前端 未结 5 792
抹茶落季
抹茶落季 2021-01-28 21:49

I will begin with an example. Suppose I need to guard a code with a function inside a mutex. There are two ways of implementing this.

#include 
#         


        
相关标签:
5条回答
  • 2021-01-28 22:17

    Here's an example using Boost.ScopeExit (untested):

    #include <boost/scope_exit.hpp>
    
    ...
    
    void threadfunc_autolock(int i, float value)
    {
        pthread_mutex_lock(&myMutex);
    
        BOOST_SCOPE_EXIT(&myMutex) {
            pthread_mutex_unlock(&myMutex);
        } BOOST_SCOPE_EXIT_END
    
        if(i <= 0 || i > myVec.size())
        {
            return;
        }
    
        if(value < 0)
        {
            return;
        }
    
        myVec[i] += value;
    }
    
    0 讨论(0)
  • 2021-01-28 22:20

    You could use something like ScopeGuard. (Now somewhat old-fashioned.)

    But given how easy and clear it is to construct a specific RAII wrapper for each resource type I would normally do that.

    (I don't think boost ever adopted anything like ScopeGuard. With std::function, lambdas and so on it's easy to do your own.)

    0 讨论(0)
  • 2021-01-28 22:29

    You may write your own geneirc RAII class, something like:

    class Finally
    {
    public:
        explicit Finally(std::function<void()> f) : mF(f) {}
        ~Finally() noexcept() {
            try
            {
                mF();
            } catch (...) {
                // Handle error.
            } 
        }
    
        Finally(const Finally&) = delete;
        Finally(Finally&&) = delete;
    
        Finally& operator=(const Finally&) = delete;
        Finally& operator=(Finally&&) = delete;
    
    private:
        std::function<void()> mF;
    };
    

    Usage:

    {
        pthread_mutex_lock(&myMutex);
        Finally finally([&](){ pthread_mutex_unlock(&myMutex); });
    
        //..
    }
    

    Even if a dedicated RAII object may be more appropriate in some case (as Mutex).

    0 讨论(0)
  • 2021-01-28 22:30

    There is a proposal for a generic scope guard to be included in the next C++ standard, and I think it is accepted. You can find an implementation here, together with a link to the reference paper.

    In principle, it is similar to the classical ScopeGuard, but it also provides some special cases e.g. for C-like file APIs.

    0 讨论(0)
  • 2021-01-28 22:35

    What's wrong with writing your own generic resource wrapper?

    template <typename Res, typename Fn = std::function<void(Res*)>>
    class resource_mgr
    {
        Res* resource;
        Fn initialize, finalize;
    
    public:
        resource_mgr (Res* r, Fn i, Fn f)
        : resource(r),
          initialize(i),
          finalize(f)
        {
            initialize(resource);
        }
    
        resource_mgr (resource_mgr const&) = delete;
        resource_mgr (resource_mgr&&)      = delete;
    
        resource_mgr const& operator = (resource_mgr const&) = delete;
        resource_mgr const& operator = (resource_mgr&&)      = delete;
    
        ~resource_mgr
        {
            try
            {
                finalize(resource);
            }
            catch(...)
            {
                std::cerr << "Uh-oh!"
            }
        }
    };
    

    You can keep it simple or go wild on something like this -- use smart pointers, define move operations, add support for custom error handlers, etc. You might use it like this:

    void threadfunc_autolock(int i, float value)
    {
        resource_mgr<mutex_t>  autoMutex (
            &myMutex,
            [](auto* p) { if (!pthread_mutex_lock(p)) throw Something(); },
            [](auto* p) { if (!pthread_mutex_unlock(p)) throw Something(); }
        );
    
        /* . . . */
    }
    
    0 讨论(0)
提交回复
热议问题