Co to jest uchwyt w C ++?


98

Powiedziano mi, że uchwyt jest swego rodzaju wskaźnikiem, ale nie, i że pozwala zachować odniesienie do obiektu, a nie do samego obiektu. Jakie jest bardziej szczegółowe wyjaśnienie?



2
Spójrz na wzorzec łańcucha odpowiedzialności, a dowiesz się, że „uchwyt” to w zasadzie węzeł, a „uchwyt” to ich mały zestaw. „Magia” pochodzi z rekursji

Odpowiedzi:


100

Uchwyt może być czymkolwiek, od indeksu liczb całkowitych do wskaźnika do zasobu w przestrzeni jądra. Chodzi o to, że zapewniają abstrakcję zasobu, więc nie musisz wiedzieć zbyt wiele o samym zasobie, aby z niego korzystać.

Na przykład, HWND w Win32 API jest uchwytem dla okna. Sam w sobie jest bezużyteczny: nie możesz z niego uzyskać żadnych informacji. Ale przekaż go do odpowiednich funkcji API, a możesz z nim wykonać wiele różnych sztuczek. Wewnętrznie możesz myśleć o HWND jako o indeksie tabeli okien GUI (co niekoniecznie musi być tak zaimplementowane, ale sprawia, że ​​magia ma sens).

EDYCJA: Brak 100% pewności, o co konkretnie pytałeś. Mowa tu głównie o czystym C / C ++.


14
Uchwyt może być przydatny do zapisywania stanów (między innymi). Jeśli masz dane w strukturze takiej jak std :: vector. Twój obiekt może znajdować się w różnych lokalizacjach pamięci w różnym czasie podczas wykonywania programu, co oznacza, że ​​wskaźnik do tej pamięci zmieni wartości. Z uchwytem nigdy się nie zmienia, zawsze odwołuje się do twojego obiektu. Wyobraź sobie, że zapisujesz stan programu (jak w grze) - nie zapisujesz lokalizacji wskaźnika do danych, a później ponownie importujesz dane i próbujesz uzyskać ten adres w pamięci. Możesz jednak zapisać uchwyt ze swoimi danymi i zaimportować dane i uchwyt.
SinisterRainbow

Czy jest możliwe przekonwertowanie HANDLE na jego odpowiednik w Linuksie? Muszę zmigrować program, który używa HANDLE z Windows na Linux.
Cornel Verster

1
To jest prawidłowa odpowiedź, że mogą to być cokolwiek i że kod, który ich używa, definiuje typ uchwytu. Próbowałem stworzyć bardziej zwięzłą wersję mojej własnej podobnej odpowiedzi, ale nie mogłem się powstrzymać, dla potomności. @CornelVerster - są takie same w Linuksie. Mam na myśli, nie uchwyty systemu operacyjnego, ale koncepcja. Zależy to więc od uchwytu, co do jego migracji, a nawet konieczności migracji.
dyasta

@Matthew Iselin: czy w jakiejkolwiek dokumentacji API określają, że jest to handler, powinniśmy wiedzieć, aby przekazać je do funkcji, w przeciwnym razie skąd możemy wiedzieć, co to jest handler w dokumentacji API
Amin Khormaei

51

Uchwyt to wskaźnik lub indeks bez dołączonego widocznego typu. Zwykle widzisz coś takiego:

 typedef void* HANDLE;
 HANDLE myHandleToSomething = CreateSomething();

Więc w swoim kodzie po prostu przekazujesz HANDLE jako nieprzezroczystą wartość.

W kodzie używającym obiektu rzutuje wskaźnik na rzeczywisty typ struktury i używa go:

 int doSomething(HANDLE s, int a, int b) {
     Something* something = reinterpret_cast<Something*>(s);
     return something->doit(a, b);
 }

Lub używa go jako indeksu do tablicy / wektora:

 int doSomething(HANDLE s, int a, int b) {
     int index = (int)s;
     try {
         Something& something = vecSomething[index];
         return something.doit(a, b);
     } catch (boundscheck& e) {
         throw SomethingException(INVALID_HANDLE);
     }
 }

29

Uchwyt jest rodzajem wskaźnika, ponieważ zazwyczaj jest sposobem odwoływania się do jakiejś jednostki.

Dokładniej byłoby powiedzieć, że wskaźnik jest jednym typem uchwytu, ale nie wszystkie uchwyty są wskaźnikami.

Na przykład uchwyt może być również indeksem do tablicy w pamięci, która odpowiada wpisowi, który sam zawiera wskaźnik do jakiegoś obiektu.

Kluczową sprawą jest to, że kiedy masz „uchwyt”, nie wiesz ani nie obchodzi Cię, w jaki sposób ten uchwyt faktycznie identyfikuje rzecz, którą identyfikuje, wszystko, co musisz wiedzieć, to to, że tak jest.

Powinno też być oczywiste, że nie ma jednej odpowiedzi na pytanie „czym właściwie jest klamka”, ponieważ uchwyty do różnych rzeczy, nawet w tym samym systemie, mogą być realizowane na różne sposoby „pod maską”. Ale nie powinieneś martwić się tymi różnicami.


6

W C ++ / CLI uchwyt jest wskaźnikiem do obiektu znajdującego się na stercie GC. Utworzenie obiektu na (niezarządzanej) stercie C ++ odbywa się za pomocą, newa wynikiem newwyrażenia jest „normalny” wskaźnik. Obiekt zarządzany jest przydzielany na stercie GC (zarządzanej) za pomocą gcnewwyrażenia. Rezultatem będzie uchwyt. Nie można wykonywać arytmetyki wskaźników na uchwytach. Nie masz wolnych uchwytów. Zaopiekuje się nimi GC. Ponadto GC może przemieszczać obiekty na zarządzanej stercie i aktualizować uchwyty, aby wskazywały nowe lokalizacje, podczas gdy program jest uruchomiony.


5

Pojawia się to w kontekście idiomu Handle-Body-Idiom , zwanego także idiomem Pimpl. Pozwala na utrzymanie tego samego ABI (binarnego interfejsu) biblioteki, poprzez przechowywanie rzeczywistych danych w innym obiekcie klasy, do którego odwołuje się tylko wskaźnik trzymany w obiekcie "uchwyt", składającym się z funkcji, które są delegowane do tej klasy " Ciało".

Przydatne jest również włączenie stałego czasu i bezpiecznej wymiany dwóch obiektów. W tym celu wystarczy zamienić wskaźnik wskazujący na obiekt ciała.


2

Uchwyt jest taki, jaki chcesz.

Uchwyt może być liczbą całkowitą bez znaku używaną w jakiejś tabeli przeglądowej.

Uchwyt może być wskaźnikiem do większego zestawu danych lub do niego.

Zależy to od tego, jak zachowuje się kod używający uchwytu. To określa typ uchwytu.

Powód, dla którego używa się terminu „ uchwyt ”, jest ważny. Oznacza to, że są to identyfikatory lub typy dostępu do obiektu. Oznacza to, że dla programisty reprezentują „klucz” lub dostęp do czegoś.


2

HANDLE hnd; jest taki sam jak void * ptr;

HANDLE to typedef zdefiniowany w pliku winnt.h w programie Visual Studio (Windows):

typedef void *HANDLE;

Przeczytaj więcej o UCHWYCIE


1
Dotyczy to tylko systemu Windows i tylko jednego z wielu typów uchwytów używanych w architekturze systemu Windows. Jednak jest to tzw. „Normalny uchwyt na poziomie aplikacji systemu Windows”.
dyasta
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.