2012-03-23 16 views
7

Mi chiedevo se esiste un modo per utilizzare unique_ptr<T> con gli HANDLE di Windows?Come utilizzare puntatori intelligenti standard C++ con Windows HANDLE?

Stavo pensando di sostituire lo std::default_delete con lo specifico che chiama CloseHandle. Il problema è che HANDLE è definito come void*unique_ptr<void> non verrà compilato come sizeof(void) non è definito.

Finora vedo solo due possibilità:

  1. creare una classe wrapper per maniglie e usare in questo modo: unique_ptr<new CHandle(h)>. Questo rende praticamente lo stesso unique_ptr<T> inutile.
  2. Utilizzare la classe di puntatore intelligente specifica HANDLE simile a unique_ptr<T>.

Quale pensi sia la scelta migliore? Che cosa suggeriresti?

La domanda può essere esteso per COM IUnknown puntatori - può CComPtr essere sostituito da uno qualsiasi dei puntatori intelligenti standard?

risposta

7

La domanda può essere esteso per COM Suggerimenti IUnknown - CComPtr può essere sostituito da uno qualsiasi dei puntatori intelligenti standard?

Sì. Non sei specializzato in std::default_deleter, devi semplicemente sostituire il tipo deleter.

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

Lo stesso principio vale per shared_ptr e anzi, a HANDLE.

6

Creare una classe di puntatore intelligente specifica, non ci vorrà molto. Non abusare delle lezioni di biblioteca. Gestire la semantica è molto diverso da quello di un puntatore C++; per prima cosa, il dereferenziamento di una MANIGLIA non ha senso.

Un altro motivo per utilizzare una classe di handle intelligente personalizzata: NULL non indica sempre un handle vuoto. A volte è INVALID_HANDLE_VALUE, che non è lo stesso (in realtà -1).

+1

Ho scritto il mio set di classi specifiche di HANDLE, poiché alcuni handle richiedono 'CloseHandle()' mentre altri richiedono diverse funzioni specifiche dell'API, alcuni HANDLE sono impostati su INVALID_HANDLE_VALUE quando non assegnati e altri sono impostati su NULL invece, ecc. Ho scritto un insieme di classi base per la maggior parte del lavoro, e poi uso classi di tratti personalizzati per gestire i problemi di chiusura e assegnazione. –

+0

-1 per reimplementare male le classi di libreria. Sono espressamente progettati per questa funzionalità, non è un abuso. Introdurrai nuovi bug e codici inutili. – Puppy

+0

+1 per riconoscere che i puntatori e gli HANDLE sono cose diverse con semantica diversa. Scaricando gli HANDLE in un tipo di puntatore intelligente si ottengono numerosi metodi che non hanno alcun senso per gli HANDLE. –

0

È necessario utilizzare CloseHandle() per "chiudere" un handle utilizzando invece delete. Verranno eliminati da Windows non appena non vengono aperti altrove. Quindi potresti scrivere un wrapper che chiama CloseHandle() invece di cancellarlo. Potresti anche scrivere la tua classe smartpointer che potrebbe essere migliore in quanto non c'è più bisogno di un wrapper.

1

È possibile creare una classe Deleter che rilascerà l'handle anziché chiamare delete().

Si può vedere in questo LINK come hanno risolto gli array Eliminazione con uno shared_ptr (unique_ptr ha anche un costruttore che riceve una classe Delete)

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

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

È possibile typedef vostro unique_ptr con un deleter personalizzato

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

un'altra soluzione

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

ispirato dalla soluzione di Alexander Drichel, qui è ancora più breve

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

Lavori in MSVC 2010. Si noti che è necessario specificare '&' per il nome della funzione in decltype() per dedurre un tipo puntatore a funzione.

1

A MANIGLIA non si chiude sempre con CloseHandle(), fate attenzione. Ad esempio, HANDLE aperto con FindNextFile() deve essere chiuso da FindClose().

Problemi correlati