Search code examples
c++visual-c++c++11visual-studio-2012unique-ptr

Using std::unique_ptr for Windows HANDLEs


I am attempting to use std::unique_ptrs to manage Windows HANDLEs in an exception-safe manner.

First I tried:

struct HandleDeleter
{
    void operator()( HANDLE handle )
    {
        if( handle )
        {
            FindVolumeClose( handle )
        }
    }
}
typedef std::unique_ptr< HANDLE, HandleDeleter > unique_vol_handle_t;

Later in my code when I try to use it:

unique_vol_handle_t volH( FindFirstVolumeW( buffer, MAX_GUID_PATH ) );

I get the following error from Visual Studio 2012RC:

1>          error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(std::nullptr_t) throw()' : cannot convert parameter 1 from 'HANDLE' to 'std::nullptr_t'
1>          with
1>          [
1>              _Ty=HANDLE,
1>              _Dx=VolumeHandleDeleter
1>          ]
1>          nullptr can only be converted to pointer or handle types

referencing the volH declaration line, immediately above.

After searching for some time, I found a blog article which basically says, add:

typedef HANDLE pointer;

to the top of the struct declaration, and all will be well.

I didn't believe it, but I tried it and it did resolve the error. I'm puzzled how defining a type (without even referencing it) could make such a difference.

Two questions:

  1. Can you explain the original error? I don't understand why the compiler is referring to std::nullptr_t/nullptr.

  2. How is it that the typedef resolves this (or at least appears to)? Is there a less 'spooky action at a distance' solution to this?


Solution

  • The implementation of unique_ptr checks for the presence of a ::pointer type on the deleter. If the deleter has a ::pointer type then this type is used as the pointer typedef on the unique_ptr. Otherwise a pointer to the first template argument is used.

    According to cppreference.com, the unique_ptr::pointer type is defined as

    std::remove_reference<D>::type::pointer if that type exists, otherwise T*