使用 *(void**)this 检查虚函数 table

Checking virtual function table using *(void**)this

unreal engine源代码在有效性检查函数中有这个位:

if (*(void**)this == nullptr)
{
    UE_LOG(LogUObjectBase, Error, TEXT("Virtual functions table is invalid."));
    return false;
}

在这种情况下,this 是指向 class 的实例化对象的指针。我了解转换和取消引用在表面上的作用,但我不太清楚这如何帮助检查 vtable 是否有效。

这里有两个不同的问题:这段代码是做什么的,它有效吗?

实现虚表的一种常见方式是在对象的基址上存储指向虚表的指针。因此,例如,在 32 位机器上,对象的前四个字节将是指向 vtable 的指针,而在 64 位机器上,对象的前八个字节将是指向 vtable 的指针。

考虑到这一点,让我们考虑一下 *(void**)this 的作用。 this 指针指向对象的基址。我们想将该对象的开头解释为指向 vtable 的指针,因此我们想获取对象底部指针的值。然而,我们没有那个指针的名字,所以我们不能通过名字查找它,而且因为 vtable 是由编译器设置的,所以没有对应于“vtable”的 C++ 类型。因此,我们将执行以下操作。我们将把我们想要读取的指针设想为 void*(指向“我们不知道其类型的东西”的指针)。this 指针正好指向 void*,因此我们将引入一个 (void**)this 的转换来表示“假装 this 指向 void*。”然后我们取消引用该指针以读取存储在那里的 void*,这是我们的 vtable 指针。总的来说,这给了我们 *(void**)this.

下一个问题是空检查为何有效。一般来说,这种安全检查是行不通的。它假定当为一个对象分配 space 时,在构造该对象之前将内存设置为全 0。假设是这种情况,如果尚未设置 vtable 指针,则分配给它的字节将为 0,这在某些 C++ 实现中被视为空指针。因此,您在此处列出的检查将读取 vtable 指针,查看它是否为空,如果为空则报告错误。

但是,这里有很多假设 - 在构造对象之前内存被清空,vtable 位于对象的确切基址等。我不熟悉的细节Unreal engine,但我认为它的设置可能是为了确保满足这些要求。