Erstens habe ich zugegeben, dass ich den Code in der Verbindung nur diagonal lese. Offensichtlich überlädt die Handle-Klasse den Dereferenzierungsoperator ( *
), um das T*
zurückzugeben, das gerade behandelt wird. Daher bedeuten die Ausdrücke in der ersten Zeile Folgendes:
this
ist ein (möglicherweise cv-qualifizierter) Handle<T> * const
. *this
ist Handle<T> &
**this
ist der Rückgabewert des operator*
des Handles, was die von Ihnen erwähnte T*
ist. T*
in eine void**
uminterpretiert. Beachten Sie, dass eine zusätzliche Indirektion hinzugefügt wird, sodass eine Dereferenzierung des Ergebnisses möglich ist und eine void* &
anstelle von T&
ergibt.
that
ergibt ein S*
, das als void**
neu interpretiert wird. Damit erhalten Sie ein paar Hinweise auf die verschiedenen Typen T*
und S*
, die auf magische Weise als void**
neu interpretiert werden. Dann führt der Code Null-Checks durch und dann , die magische Zeile:
Was vergleicht die (möglicherweise nicht ausgerichteten!) ersten sizeof(void*)
Bytes der Objekte% T
und S
, auf die tatsächlich zeigt co_de% und a
. Wenn Sie nicht absolut sicher sein können, dass b
und T
die richtige Größe und Ausrichtung haben, ist die Überprüfung völlig falsch. Zum Beispiel würde die Überprüfung sinnvoll sein, wenn Sie wissen, dass S
selbst immer ein Zeiger- oder Smart-Pointer-Objekt mit der gleichen Größe eines Zeigers ist, sodass verschiedene Ziehpunkte auf verschiedene Zeigerobjekte zeigen können die dennoch (in der 2. Indirektionsebene) auf das gleiche Objekt zeigen. Dies ermöglicht dem GC, das zugrunde liegende Objekt zu verschieben, ohne alle Handles darauf aktualisieren zu müssen, indem einfach der Inhalt der Zeiger der 1. Ebene aktualisiert wird.
Also, um Ihre Frage zu beantworten, nur auf T
zu werfen (ohne die Indirektion zu erhöhen) ist nicht das selbe wie der Code eingecheckt wird - Ihre Version würde die Zeiger vergleichen, also in In meinem Beispiel könnten zwei verschiedene Handles für dasselbe Objekt ungleich mit Ihrem alternativen Code verglichen werden.
PS: Es ist auch ein schlechter Stil, wenn Ihre Klasse void*
sowohl von T*
als auch von operator*
zurückgibt, weil Sie dann die allgemeine Identität zwischen operator->
und p->x
brechen. Der de-referenzierende Operator sollte generell (*p).x
zurückgeben, wenn der Benutzerzugriffsoperator ein T&
zurückgibt.
Javier Martín hat Recht. Sie können Zeiger nicht einfach vergleichen, wenn Sie in Frage gestellt haben. Vor allem im Kontext von ov v8 hat der Handle<T>
eine Einschränkung für den Typ T
. Sie können keine Klasse verwenden und Handle darauf anwenden. T
ist nur eine Fassadenklasse, die der Benutzer behandelt: v8::String
, v8::Integer
und so weiter. Das Objekt solcher Typen wird nie erstellt, aber solche Klassen werden als Schnittstellen zu Interna verwendet.
In Wirklichkeit ist der Zeiger, den Handle<>
speichert, ein Zeiger auf etwas, sagen wir "Tag". Wir haben das gleiche Objekt, auf das zwei Handle<>
verweisen, wenn ihre Tags identisch sind. Internes Tag hat die Größe von void*
und bezieht sich irgendwie auf das reale Objekt. Der Benutzer muss nicht wissen, welcher Tag so ist.% Co_de% verwendet stattdessen Handle<>
. Einige Gedanken
void*
hat Handle<T>
- & gt; Tag (nicht T*
) - (irgendwie) - & gt; echtes Objekt (nicht vom Typ T)
Der Tag hat die Größe von T
. Und der Benutzer muss nicht über den echten Tag-Typ Bescheid wissen.
Zwei Tags sind gleich - sie beziehen sich auf dasselbe Objekt.
(Zusammenfassung, vom Benutzer Sicht der Ansicht) void*
hat Handle<T>
- & gt; void**
Also tut das ursprüngliche void*
was zu tun ist: Vergleichen Sie Werte von Tags. Aber überprüfe zuerst die Zeiger.
Tags und Links c++ v8 reinterpret-cast