C++ 如何使用C++;带Windows句柄的标准智能指针?

C++ 如何使用C++;带Windows句柄的标准智能指针?,c++,winapi,c++11,C++,Winapi,C++11,我想知道是否有一种方法可以将unique\u ptr与Windows句柄一起使用 我想用调用CloseHandle的特定handle\u策略替换std::default\u delete。问题是HANDLE被定义为void*unique\u ptr不会编译为sizeof(void)未定义 到目前为止,我只看到两种可能性: 为句柄创建一个包装类,并像这样使用它:unique\u ptr。这几乎使独特的\u ptr本身毫无用处 使用类似于unique\ptr的HANDLE特定智能指针类 你认为什么是

我想知道是否有一种方法可以将
unique\u ptr
与Windows句柄一起使用

我想用调用
CloseHandle
的特定
handle\u策略替换
std::default\u delete
。问题是
HANDLE
被定义为
void*
unique\u ptr
不会编译为
sizeof(void)
未定义

到目前为止,我只看到两种可能性:

  • 为句柄创建一个包装类,并像这样使用它:
    unique\u ptr
    。这几乎使
    独特的\u ptr
    本身毫无用处
  • 使用类似于
    unique\ptr
    HANDLE
    特定智能指针类
  • 你认为什么是更好的选择?你有什么建议


    这个问题可以扩展到
    COM IUnknown
    指针-可以用任何标准智能指针替换
    CComPtr
    吗?

    创建一个特定的智能指针类,不会花费很长时间。不要滥用图书馆课程。句柄语义与C++指针有很大的不同;首先,取消对句柄的引用毫无意义


    使用自定义智能句柄类的另一个原因-NULL并不总是意味着一个空句柄。有时它是无效的\u HANDLE\u值,它不相同(实际上是-1)。

    您必须使用
    CloseHandle()
    来“关闭”句柄,而不是使用
    delete
    。一旦它们没有在其他地方打开,Windows将立即删除它们。因此,您可以编写一个调用CloseHandle()的包装器,而不是删除它。您还可以编写自己的smartpointer类,这可能会更好,因为不再需要包装器。

    您可以创建一个将释放句柄的Deleter类,而不是调用delete()

    您可以在此中看到他们如何解决使用共享\u ptr删除数组的问题(unique\u ptr还有一个接收Delete类的构造函数)

    这个问题可以扩展到COM IUnknown指针-can CComPtr 是否被任何标准智能指针所取代

    对。您不需要专门化
    std::default\u deleter
    ,只需替换deleter类型

    struct COMDeleter {
        template<typename T> void operator()(T* ptr) {
            ptr->Release();
        }
    };
    unique_ptr<IUnknown, COMDeleter> ptr; // Works fine
    
    struct-comdeter{
    模板无效运算符()(T*ptr){
    ptr->Release();
    }
    };
    唯一的\u ptr ptr;//很好
    

    同样的原则也适用于
    shared\u ptr
    ,事实上,对于
    HANDLE
    ,您可以使用自定义删除器键入您的
    unique\u ptr

    struct handle_deleter
    {
        void operator()(void* handle)
        {
            if(handle != nullptr)
                CloseHandle(handle);
        }
    };
    
    typedef std::unique_ptr<void, handle_deleter> UniqueHandle_t;
    UniqueHandle_t ptr(CreateFile(...));
    
    struct handle\u deleter
    {
    void运算符()(void*句柄)
    {
    if(handle!=nullptr)
    关闭手柄(手柄);
    }
    };
    typedef std::unique_ptr UniqueHandle_t;
    UniqueHandle_t ptr(CreateFile(…);
    
    我不建议使用带句柄的智能指针

    我建议你仔细看看

    就我个人而言,我正在利用该提案的参考实现,而不是在这些情况下使用
    std::unique\u ptr

    另一种解决方案

    std::unique_ptr< void, void(*)( HANDLE ) > uniqueHandle( file, []( HANDLE h ) { ::CloseHandle( h ); } );
    
    std::unique_ptruniqueHandle(文件,[](句柄h){::CloseHandle(h);});
    
    受亚历山大·德里切尔解决方案的启发,这里的篇幅更短

    std::unique_ptr< HANDLE, decltype(&CloseHandle) > uniqueHandle( nullptr, CloseHandle );
    
    std::unique_ptruniqueHandle(nullptr,CloseHandle);
    

    在MSVC 2010工作。请注意,您需要在decltype()中为函数名指定“&”,以推断函数类型的指针。

    句柄并不总是使用CloseHandle()关闭,请注意。 例如,使用FindTextFile()打开的句柄必须由FindClose()关闭。

    这里有一个方便的小“自定义”我用来处理
    句柄。
    
    C++17
    是编译此文件所必需的。这个想法是从另一个SO帖子中提出来的,我只添加了
    std::remove\u pointer\t
    ,这样我就不必将
    void
    作为
    自定义ptr
    类型参数传递

    定义

    #include <type_traits>
    #include <memory>
    
    template<auto fn>
    using deleter_from_fn = std::integral_constant<decltype( fn ), fn>;
    
    template<typename T, auto fn>
    using custom_ptr = std::unique_ptr<typename std::remove_pointer_t<T>, deleter_from_fn<fn>>;
    
    #包括
    #包括
    模板
    使用deleter_from_fn=std::integral_常量;
    模板
    使用custom_ptr=std::unique_ptr;
    
    使用

    custom_ptr<HANDLE, &CloseHandle> phandle{
        CreateFileMapping( INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 1024, L"FileName" ) };
    
    custom_ptr phandle{
    CreateFileMapping(无效的\u句柄\u值,空ptr,页\u读写,0,1024,L“文件名”);
    
    我编写了自己的设置句柄特定类,因为有些句柄需要
    CloseHandle()
    而其他句柄需要不同的API特定函数,有些句柄在未赋值时设置为无效的句柄值,而其他句柄则设置为空值,等等。我为大部分工作编写了一组基类,然后使用自定义特征类来处理闭包和分配问题。-1用于错误地重新实现库类。它们是专门为这个功能设计的,这不是滥用。您将引入无意义的新错误和代码。+1用于识别指针和句柄是具有不同语义的不同事物。将句柄硬塞入智能指针类型会给您提供一系列对句柄没有实际意义的方法。
    custom_ptr<HANDLE, &CloseHandle> phandle{
        CreateFileMapping( INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 1024, L"FileName" ) };