Search code examples
c++shared-ptrraii

Getting shared_ptr to call a member function once its reference count reaches 0


I'm creating a wrapper for a HANDLE that does not work with DuplicateHandle, so instead I am trying to wrap the handle in a shared_ptr.

Imagine the following code:

class CWrapper
{
public:
    CWrapper() :
        m_pHandle(new HANDLE, &CWrapper::Close)
    {
        //code to open handle
    }

private:
    void Close() 
    { 
        //code to close handle
    }

    std::shared_ptr<HANDLE> m_pHandle;
}

I have also tried creating close with a HANDLE parameter (not ideal). Either way, I get the compiler error "Term does not evaluate to a function taking 0 arguments". Is this because of the implicit this pointer? How do I fix this? How do I call a member function from the shared pointer?


Solution

  • I think you have your abstractions the wrong way around.

    shared_ptr gives you a copyable "handle" to a shared resource that can't itself be copied. Using shared_ptr with a type that doesn't perform its own cleanup when it is deleted isn't an optimal use.

    If make your class' single responsibility to clean up this inherently non-copyable resource properly in its destructor, then you can use shared_ptr to provide shared ownership which is what its single responsibility should be. (I consider HANDLE to be non-copyable as if you try to make a simple copy of a HANDLE the copies cannot be treated as independent; the last copy must be correctly closed so the owners of copies would need to know about other copies in existence.)

    class CWrapper
    {
    public:
        CWrapper()
        {
            // code to open handle
        }
    
        ~CWrapper()
        {
            // code to close handle
        }
    
    private:
        // prevent copying
        CWrapper(const CWrapper&);
        CWrapper& operator=(const CWrapper&);
    
        HANDLE mHandle;
    };
    

    Now use shared_ptr<CWrapper> where you need to shared the handle, you can use a typedef if you think that this is too verbose.

    A custom deleter is an overly complex solution, IMHO.