为什么在这里使用虚空**?
why it use void** here?
从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;
也会很好用吗?
如果a
和b
的类型为void*
,那么您不能取消引用它们(不先将它们强制转换为其他内容),因此*a == *b
不起作用。
首先,我承认我只对角线阅读链接中的代码。显然,Handle 类重载取消引用运算符 (*
) 以返回正在处理的T*
。因此,第一行中的表达式含义如下:
this
是一个(可能符合CV条件的)Handle<T> * const
。*this
Handle<T> &
**this
是句柄operator*
的返回值,这是您提到的T*
。- 最后,该
T*
被重新解释为void**
。请注意,将添加一个额外的间接寻址,因此可以取消引用结果,并且会产生void* &
而不是T&
- 与
that
的等效线生成一个S*
,该被重新解释为void**
。
因此,您可以获得一些指向不同类型的T*
和S*
的指针,这些指针神奇地重新解释为void**
.然后代码执行空检查,然后是魔术行:
return *a == *b;
这是比较a
和b
实际指向的T
和S
类型的对象的前sizeof(void*)
字节。除非您能完全确定T
和S
具有正确的大小和对齐方式,否则检查完全是假的。例如,如果您知道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::String
、v8::Integer
等。此类类型的对象永远不会创建,但此类类用作内部结构的接口。
实际上,Handle<>
存储的指针是指向 tomething 的指针,例如"Tag"。我们有相同的对象,如果它们的标签相同,则两个Handle<>
引用。内部标签的大小为void*
,并以某种方式引用真实对象。用户不需要知道 Tag 是什么,因此Handle<>
改用void*
。一些想法
-
Handle<T>
有T*
--> 标签(不是T
)--(不知何故)-->真实对象(不是T类型) -
标签的大小为
void*
。并且用户不需要知道标签的真实类型。 -
两个标签相等 - 它们引用同一个对象。
-
(总结,从用户视线来看)
Handle<T>
有void**
-->void*
因此,原始bool operator==(Handle<S> that)
正在做应该做的事情:比较标签的值。但首先检查指针。
- 为什么thread_local变量在这里从未初始化?
- 为什么我必须在这里使用dynamic_cast
- 为什么 C++20 中的 [[可能]] 属性在这里引发警告?
- 为什么gmp会在这里与"invalid next size"重新定位一起崩溃?
- 为什么枚举变量在这里是右值?
- 为什么sizeof函数在这里不能正常工作
- 为什么我在这里收到C++没有已知的转换错误?
- 为什么在这里使用 int64_t 错误和 int 可以编译?
- C++ 互斥锁可以交叉方法/变量吗?如果是这样,为什么在这里不起作用?
- 为什么 GetExitCodeThread() 在这里返回 FALSE?
- 为什么我在这里遇到分段错误?[Python ctypes]
- 为什么在这里再次宣布宣布的课程?
- 为什么我收到此错误:constexpr' 在这里无效
- 为什么在这里可以使用"删除"?
- 使用大括号实例化 - 它是什么,为什么在这里使用它?
- 为什么我们在这里将 0 添加到双空指针上?
- 不明白为什么动态编程在这里不起作用
- 为什么/如何在这里除法和乘法同样快?
- 为什么在这里调用析构函数,以及在调用该对象析构函数后如何调用对象成员函数?
- 为什么在提到 prvalue 时,它在这里使用术语"object"?