2012-03-23 17 views
7

Me preguntaba si hay una forma de usar unique_ptr<T> con Windows HANDLEs?¿Cómo utilizar los punteros inteligentes estándar de C++ con Windows HANDLEs?

Estaba pensando en reemplazar el std::default_delete con handle_trats que llama al CloseHandle. El problema es que HANDLE se define como void*unique_ptr<void> no se compilará ya que sizeof(void) no está definido.

Hasta ahora sólo veo dos posibilidades:

  1. crear una clase contenedora para las manijas y utilizar de esta manera: unique_ptr<new CHandle(h)>. Esto hace que el unique_ptr<T> sea inútil.
  2. Utilice HANDLE clase específica de puntero inteligente que se asemeje a unique_ptr<T>.

¿Cuál cree que es la mejor opción? ¿Qué sugieres?

La pregunta se puede ampliar para COM IUnknown punteros - ¿puede reemplazarse CComPtr por alguno de los punteros inteligentes estándar?

Respuesta

7

La pregunta puede ser extendido para COM IUn punteros conocidos: ¿se puede reemplazar CComPtr por alguno de los punteros inteligentes estándar?

Sí. No se especializa en std::default_deleter, simplemente reemplace el tipo de eliminador.

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

El mismo principio se aplica a shared_ptr y, de hecho, a HANDLE.

6

Crear una clase de puntero inteligente específica, no llevará mucho tiempo. No abuse de las clases de la biblioteca. La semántica de Handle es bastante diferente de la de un puntero de C++; por un lado, quitarle una referencia a HANDLE no tiene sentido.

Una razón más para usar una clase de controlador inteligente personalizada: NULL no siempre significa un identificador vacío. A veces es INVALID_HANDLE_VALUE, que no es lo mismo (en realidad -1).

+1

Escribí mis propias clases específicas de HANDLE, ya que algunas manecillas requieren 'CloseHandle()' mientras que otras requieren diferentes funciones específicas de API, algunas HANDLEs se configuran en INVALID_HANDLE_VALUE cuando no están asignadas y otras en NULL, etc. Escribí un conjunto de clases base para la mayor parte del trabajo, y luego uso clases de características personalizadas para manejar problemas de cierre y asignación. –

+0

-1 para volver a implementar mal las clases de biblioteca. Están explícitamente diseñados para esta funcionalidad, no es un abuso. Introducirá nuevos códigos y errores inútiles. – Puppy

+0

+1 para reconocer que los punteros y los MANIPULADORES son cosas diferentes con semántica diferente. Shoehorning HANDLEs en un tipo de puntero inteligente le ofrece un conjunto de métodos que realmente no tienen sentido para HANDLEs. –

0

Debe usar CloseHandle() para "cerrar" una manija en su lugar usando delete. Ellos serán eliminados por Windows tan pronto como no se abran en otro lugar. Por lo tanto, podría escribir un contenedor que llame a CloseHandle() en lugar de eliminarlo. También podría escribir su propia clase de smartpointer, que podría ser mejor, ya que no hay necesidad de un contenedor.

1

Puede crear una clase Deleter que liberará el identificador en lugar de llamar a delete().

Se puede ver en este LINK forma en que han resuelto matrices eliminando con un shared_ptr (unique_ptr también tiene un constructor que recieves una clase Delete)

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

    HANDLE blah = GetSomeHandle(); 
    unique_ptr myPointer(blah,handle_deleter); 
2

Puede typedef su unique_ptr con un Deleter encargo

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(...)); 
1

otra solución

std::unique_ptr< void, void(*)(HANDLE) > uniqueHandle(file, [](HANDLE h) { ::CloseHandle(h); }); 
1

inspirado en la solución de Alexander Drichel, aquí es aún más corto

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

Obras en MSVC 2010. Tenga en cuenta que es necesario especificar '&' para el nombre de función en decltype() para deducir un tipo de puntero a función.

1

A HANDLE no siempre se cierra con CloseHandle(), tenga cuidado. Por ejemplo, un identificador abierto con FindNextFile() debe ser cerrado por FindClose().

Cuestiones relacionadas