为什么在这里使用虚空**?

why it use void** here?

本文关键字:在这里 为什么      更新时间:2023-10-16

从v8-0.2.5拾取的代码

/**
* Checks whether two handles are the same.
* Returns true if both are empty, or if the objects
* to which they refer are identical.
* The handles' references are not checked.
*/
template <class S> bool operator==(Handle<S> that) {
void** a = reinterpret_cast<void**>(**this);
void** b = reinterpret_cast<void**>(*that);
if (a == 0) return b == 0;
if (b == 0) return false;
return *a == *b;
}  

Handle重载运算符*,以便**this*that返回类型T*

所以看起来

void* a = reinterpret_cast<void*>(**this);
void* b = reinterpret_cast<void*>(*that);
return a == b;

也会很好用吗?

如果ab的类型为void*,那么您不能取消引用它们(不先将它们强制转换为其他内容),因此*a == *b不起作用。

首先,我承认我只对角线阅读链接中的代码。显然,Handle 类重载取消引用运算符 (*) 以返回正在处理的T*。因此,第一行中的表达式含义如下:

  • this是一个(可能符合CV条件的)Handle<T> * const
  • *thisHandle<T> &
  • **this是句柄operator*的返回值,这是您提到的T*
  • 最后,该T*被重新解释为void**。请注意,将添加一个额外的间接寻址,因此可以取消引用结果,并且会产生void* &而不是T&
  • that的等效线生成一个S*,该被重新解释为void**

因此,您可以获得一些指向不同类型的T*S*的指针,这些指针神奇地重新解释为void**.然后代码执行空检查,然后是魔术行:

return *a == *b;

这是比较ab实际指向的TS类型的对象的sizeof(void*)字节除非您能完全确定TS具有正确的大小和对齐方式,否则检查完全是假的。例如,如果您知道T本身始终是指针大小相同的指针或智能指针对象,则检查是有意义的,因此您可能有不同的句柄指向不同的指针对象,但这些指针对象仍然指向(在第二个间接寻址级别)指向同一对象。这允许 GC 移动基础对象,而无需更新其所有句柄,只需更新第一级指针的内容即可。

Handle<T> has T* -----> T = U* pinned in memory -----> actual object U can be moved

因此,为了回答您的问题,仅强制转换为void*(不增加间接寻址)签入代码不同 - 您的版本将比较指针,因此在我的示例中,同一对象的两个不同句柄可能会与您的备用代码不相等。

PS:让你的班级从operator*operator->返回T*也是不好的风格,因为那样你就打破了p->x(*p).x之间的一般身份。如果成员访问运算符返回T*,则取消引用运算符通常应返回T&

哈维尔·马丁是对的。你不能只是比较指针,因为你有问题。首先,在上下文ov v8中,Handle<T>对类型T有限制。您不能接受任何类并对其应用 Handle。T只是用户处理的一个外观类:v8::Stringv8::Integer等。此类类型的对象永远不会创建,但此类类用作内部结构的接口。

实际上,Handle<>存储的指针是指向 tomething 的指针,例如"Tag"。我们有相同的对象,如果它们的标签相同,则两个Handle<>引用。内部标签的大小为void*,并以某种方式引用真实对象。用户不需要知道 Tag 是什么,因此Handle<>改用void*。一些想法

  1. Handle<T>T*--> 标签(不是T)--(不知何故)-->真实对象(不是T类型)

  2. 标签的大小为void*。并且用户不需要知道标签的真实类型。

  3. 两个标签相等 - 它们引用同一个对象。

  4. (总结,从用户视线来看)Handle<T>void**-->void*

因此,原始bool operator==(Handle<S> that)正在做应该做的事情:比较标签的值。但首先检查指针。