2012-03-23 16 views
7

Zastanawiam się, czy istnieje sposób użycia unique_ptr<T> z uchwytami systemu Windows?Jak używać standardowych inteligentnych wskaźników C++ z uchwytami systemu Windows?

Zastanawiam się nad zastąpieniem std::default_delete specyficznym handle_trats, który wywołuje CloseHandle. Problem polega na tym, że HANDLE jest zdefiniowany jako void*unique_ptr<void> nie zostanie skompilowany, ponieważ sizeof(void) nie jest zdefiniowany.

tej pory widzę tylko dwie możliwości:

  1. utworzyć klasy otoki do klamek i używać go tak: unique_ptr<new CHandle(h)>. To sprawia, że ​​sama unique_ptr<T> jest bezużyteczna.
  2. Użyj konkretnej klasy inteligentnego wskaźnika, która przypomina unique_ptr<T>.

Co według Ciebie jest lepszym wyborem? Co byś zasugerował?

Pytanie może zostać przedłużone o COM IUnknown wskaźników - czy CComPtr może zostać zastąpiony przez jeden ze standardowych inteligentnych wskaźników?

Odpowiedz

7

Pytanie może zostać przedłużona na COM Nieznane wskaźniki - czy CComPtr może zostać zastąpiony przez jeden ze standardowych inteligentnych wskaźników?

Tak. Nie specjalizujesz się w std::default_deleter, po prostu zastępujesz typ deletera.

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

Ta sama zasada ma zastosowanie do shared_ptr i rzeczywiście, do HANDLE.

6

Utwórz konkretną klasę inteligentnego wskaźnika, która nie potrwa długo. Nie nadużywaj klas bibliotecznych. Obsługa semantyki jest zupełnie inna niż w przypadku wskaźnika C++; po pierwsze, dereferencja RĘKI nie ma sensu.

Kolejny powód, dla którego warto używać niestandardowej klasy inteligentnego uchwytu - NULL nie zawsze oznacza pustą klamkę. Czasami jest to INVALID_HANDLE_VALUE, co nie jest takie samo (właściwie -1).

+1

Napisałem własne ustawienia dla konkretnych klas, ponieważ niektóre uchwyty wymagają 'CloseHandle()', podczas gdy inne wymagają innych funkcji specyficznych dla API, niektóre HANDLE są ustawione na INVALID_HANDLE_VALUE, gdy nie są przypisane, a inne ustawione są na NULL zamiast itd. Napisałem zestaw klas bazowych dla większości prac, a następnie używam niestandardowych klas cech do obsługi problemów związanych z zamknięciem i przydziałem. –

+0

-1 w celu ponownego wprowadzenia klas bibliotek źle. Są one wyraźnie zaprojektowane dla tej funkcjonalności, to nie jest nadużycie. Wprowadzisz bezcelowe nowe błędy i kod. – Puppy

+0

+1 za rozpoznanie, że wskaźniki i UCHWYTY są różnymi rzeczami o różnej semantyki. Shoehorning HANDLEs to inteligentny typ wskaźnika, który oferuje wiele metod, które nie mają większego sensu w przypadku HANDLE. –

0

Musisz użyć CloseHandle(), aby "zamknąć" uchwyt zamiast używać delete. Zostaną one usunięte przez system Windows, gdy tylko nie zostaną otwarte w innym miejscu. Więc możesz napisać wrapper, który wywołuje CloseHandle() zamiast go usuwać. Możesz również napisać własną klasę inteligentnego sprytu, która może być lepsza, ponieważ nie ma już potrzeby otoki.

1

Możesz utworzyć klasę Deleter, która zwolni uchwyt zamiast wywoływać delete().

można zobaczyć w tym LINK jak oni rozwiązali tablice usuwając z shared_ptr (unique_ptr posiada również konstruktor recieves Usuń klasa)

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

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

Można typedef swoją unique_ptr z niestandardowym Deleter

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

jeszcze inne rozwiązanie

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

zainspirowany rozwiązania Alexander Drichel, oto jest jeszcze krótszy

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

Works w MSVC 2010. Należy zauważyć, że trzeba określić '&' dla nazwy funkcji w decltype() w celu dedukcji typu wskaźnik-funkcja.

1

Uchwyty nie zawsze są zamykane przy użyciu funkcji CloseHandle(), uwaga. Na przykład UCHWYT otwarty przy pomocy FindNextFile() musi zostać zamknięty przez FindClose().

Powiązane problemy