One-liner for RAII on non pointer?

前端 未结 6 1781
小蘑菇
小蘑菇 2020-12-24 08:31

Related topic

std::unique_ptr, deleters and the Win32 API

To use a Win32 Handle as a RAII, I can use the following line

std:         


        
6条回答
  •  不思量自难忘°
    2020-12-24 09:09

    Finally, I want with another Kerrek SB answer. It's the proposal for STD Unique Resource.

    #ifndef UNIQUE_RESOURCE_H_
    #define UNIQUE_RESOURCE_H_
    
    #include 
    
    // From standard proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3949.pdf
    // Slightly modified to compile on VS2012.
    namespace std
    {
        namespace experimental
        {
            enum class invoke_it { once, again };
            template
            class unique_resource_t 
            {
                R resource;
                D deleter;
                bool execute_on_destruction; // exposition only
                unique_resource_t& operator=(unique_resource_t const &);
                unique_resource_t(unique_resource_t const &); // no copies!
            public:
                // construction
                explicit unique_resource_t(R && resource, D && deleter, bool shouldrun=true)
                    : resource(std::move(resource))
                    , deleter(std::move(deleter))
                    , execute_on_destruction(shouldrun)
                {
    
                }
                // move
                unique_resource_t(unique_resource_t &&other) /*noexcept*/
                    :resource(std::move(other.resource))
                    ,deleter(std::move(other.deleter))
                    ,execute_on_destruction(other.execute_on_destruction)
                {
                        other.release();
                }
                unique_resource_t& operator=(unique_resource_t &&other) 
                {
                    this->invoke(invoke_it::once);
                    deleter=std::move(other.deleter);
                    resource=std::move(other.resource);
                    execute_on_destruction=other.execute_on_destruction;
                    other.release();
                    return *this;
                }
                // resource release
                ~unique_resource_t() 
                {
                    this->invoke(invoke_it::once);
                }
                void invoke(invoke_it const strategy = invoke_it::once) 
                {
                    if (execute_on_destruction) {
                        try {
                            this->get_deleter()(resource);
                        } catch(...){}
                    }
                    execute_on_destruction = strategy==invoke_it::again;
                }
                R const & release() /*noexcept*/{
                    execute_on_destruction = false;
                    return this->get();
                }
                void reset(R && newresource) /*noexcept*/ {
                    invoke(invoke_it::again);
                    resource = std::move(newresource);
                }
                // resource access
                R const & get() const /*noexcept*/ {
                    return resource;
                }
                operator R const &() const /*noexcept*/ 
                {
                    return resource;
                }
                R operator->() const /*noexcept*/ 
                {
                    return resource;
                }
    
    //             Couldn't make this function compile on VS2012
    //             std::add_lvalue_reference::type>::type operator*() const 
    //             {
    //                     return * resource;
    //             }
    
                // deleter access
                const D & get_deleter() const /*noexcept*/ 
                {
                    return deleter;
                }
            };
    
            //factories
            template
            unique_resource_t unique_resource( R && r,D t) /*noexcept*/ 
            {
                    return unique_resource_t(std::move(r), std::move(t),true);
            }
                template
            unique_resource_t
                unique_resource_checked(R r, R invalid, D t ) /*noexcept*/ {
                    bool shouldrun = (r != invalid);
                    return unique_resource_t(std::move(r), std::move(t), shouldrun);
            }
        }
    }
    #endif /* UNIQUE RESOURCE H */
    

    Usage

    auto listenSocket = std::experimental::unique_resource_checked(socket(AF_INET,SOCK_STREAM,IPPROTO_TCP), INVALID_SOCKET, closesocket);
    

    Hope this makes std soon enough!

提交回复
热议问题