Как использовать стандартные умные указатели C ++ с Windows HANDLE? - PullRequest
8 голосов
/ 23 марта 2012

Мне было интересно, есть ли способ использовать unique_ptr<T> с Windows HANDLEs?

Я думал заменить std::default_delete на конкретный handle_trats, который вызывает CloseHandle. Проблема в том, что HANDLE определено как void* unique_ptr<void> не будет компилироваться, поскольку sizeof(void) не определено.

Пока я вижу только две возможности:

  1. Создайте класс-оболочку для HANDLE и используйте его следующим образом: unique_ptr<new CHandle(h)>. Это в значительной степени делает бесполезным unique_ptr<T>.
  2. Используйте HANDLE определенный класс интеллектуальных указателей, который напоминает unique_ptr<T>.

Как вы думаете, какой выбор лучше? Что ты предлагаешь?

Вопрос может быть расширен для COM IUnknown указателей - можно ли CComPtr заменить любым из стандартных интеллектуальных указателей?

Ответы [ 9 ]

9 голосов
/ 23 марта 2012

Вопрос может быть расширен для COM IUnknown указателей - можно CComPtr заменить какими-либо стандартными умными указателями?

Да. Вы не специализируете std::default_deleter, вы просто заменяете тип средства удаления.

struct COMDeleter {
    template<typename T> void operator()(T* ptr) {
        ptr->Release();
    }
};
unique_ptr<IUnknown, COMDeleter> ptr; // Works fine

Тот же принцип применим к shared_ptr и действительно к HANDLE.

6 голосов
/ 23 марта 2012

Создайте определенный класс интеллектуальных указателей, это не займет много времени.Не злоупотребляйте занятиями в библиотеке.Семантика дескриптора весьма отличается от таковой для указателя C ++;с одной стороны, разыменование HANDLE не имеет смысла.

Еще одна причина использовать собственный класс умного дескриптора - NULL не всегда означает пустой дескриптор.Иногда это INVALID_HANDLE_VALUE, что не совпадает (на самом деле -1).

3 голосов
/ 04 июня 2013

еще одно решение

std::unique_ptr< void, void(*)( HANDLE ) > uniqueHandle( file, []( HANDLE h ) { ::CloseHandle( h ); } );
3 голосов
/ 23 марта 2012

Вы можете ввести unique_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(...));
2 голосов
/ 08 октября 2014

вдохновленный решением Александра Дричела, здесь еще короче

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

Работает в MSVC 2010. Обратите внимание, что вам нужно указать '&' для имени функции в decltype (), чтобы определить тип указателя на функцию.

1 голос
/ 10 января 2015

РУЧКА не всегда закрывается с помощью CloseHandle (), будьте осторожны. Например, HANDLE, открытый с FindNextFile (), должен быть закрыт FindClose ().

1 голос
/ 16 февраля 2013

Я не рекомендую использовать умные указатели с ручками.

Я рекомендую вам взглянуть на Предложение добавить дополнительные оболочки RAII в стандартную библиотеку и недостатки использования умных указателей с ручками .

Лично я использую эталонную реализацию этого предложения вместо std::unique_ptrдля этих ситуаций.

1 голос
/ 23 марта 2012

Вы можете создать класс Deleter, который будет освобождать дескриптор вместо вызова delete ().

В этом LINK показано, как они решилиудаление массивов с помощью shared_ptr (unique_ptr также имеет конструктор, который получает класс Delete)

  struct handle_deleter
  {   
    void operator ()( HANDLE handle)
      { CloseHandle(p); }
  };

  HANDLE blah = GetSomeHandle();
  unique_ptr myPointer(blah,handle_deleter);
0 голосов
/ 23 марта 2012

Вы должны использовать CloseHandle(), чтобы «закрыть» дескриптор вместо использования delete.Они будут удалены Windows, как только они не будут открыты в другом месте.Таким образом, вы можете написать оболочку, которая вызывает CloseHandle () вместо того, чтобы удалять ее.Вы также можете написать свой собственный класс smartpointer, который может быть лучше, так как больше не требуется обёртка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...