问题标签 [vptr]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - 在 MSVC ABI 中,如何可靠地找到仅给定 (void*) 的 vtable?
这个问题专门关于非便携式 MSVC ABI 的东西。
我正在尝试typeid
用明显不可移植但非魔术的 C++ 编写相当于 C++ 的代码。对于 Itanium ABI(在 Linux/Mac 上使用),这非常简单:
所以现在我正在查看 64 位 MSVC ABI,但它,我被难住了。对于非常简单的类,在偏移量 0 处以 vfptr 开头的类,它几乎和 Itanium 一样简单:
(此代码基于Wine 项目的__RTtypeid
.)
问题是某些 C++ 类不是以偏移 0 处的 vfptr 开头!有时它们以 vbptr 开头。
Class1
以 vfptr 开头;Class2
以 vbptr 开头。
当一个类以 vbptr 开头时,我相信它的第一个虚拟基础子对象(它在布局顺序中的第一个,因此它的“最叶”)总是在其偏移量 0 处有一个 vfptr。所以如果我知道我'我处理一个以 vbptr 开头的类,我想这样做:
我已经确定MSVC 确实生成了相当于
在编译 C++ 表达式时typeid(x)
——这IS_VBPTR_CLASS
是“编译器神奇地知道是否x
有 vbptr,基于静态类型x
和编译器知道每种类型的布局的事实”的伪代码。
但是,在我的情况下,我不知道 的静态类型x
,即使我知道,我也不知道如何(从 C++ 中,使用模板元编程)找出是否x
以 vbptr 开头。
最后,我继续用
只是发现存储在 vftable 中的“Class2 中的 Class1”的类型信息包含子对象类型的类型信息Class1
,而不是最派生类型的类型信息Class2
!所以还有一块拼图缺失了。
所以我的问题简而言之:鉴于(void*)&object_of_type_class2
,我该如何检索typeid(Class2)
?
c++ - 从文件中读取对象后无法调用虚拟成员函数
问题:
我使用二进制模式将对象写入文件std::fstream
。但是,当我从该文件将其读回另一个对象,然后调用该新对象的其中一个虚拟成员函数时,会出现内存访问冲突错误。
代码如下所示:
我发现了什么:
经过几个小时的调试,我看到__vfptr
成员b
(据我所知,它是指向该对象的虚拟表的指针)在文件读取语句之后发生了变化。我想我不仅将数据写入a
到文件并将它们复制到,我还复制了到b
的虚拟表指针。a
b
我说的对吗?我该如何解决这个问题?
c++ - 虚拟表和_vptr存储方案
有人可以解释这个不同类的虚拟表是如何存储在内存中的吗?当我们使用指针调用函数时,他们如何使用地址位置调用函数?我们可以使用类指针获得这些虚拟表内存分配大小吗?我想看看一个类的虚拟表使用了多少内存块。我怎么能看到它?
谢谢!提前
c++ - 如何在 C++ 汇编代码中找到 VPTR?
我使用 gcc 5.4.0 编译代码,并使用objdump -S a.out
反汇编二进制文件。我想找到 Base 的 vptr,但只显示一个未知地址0x80487d4
。最大地址数是0x80487b7
,我看不懂。命令列表:g++ test.cpp -O0; objdump -S a.out
c++ - 在 C 中使用带有虚拟成员(即非 POD)的 C++ 结构
在诸如此类的问题中,只要所有成员的类型相同,顺序相同,并且没有声明任何虚拟成员,就尽可能解释 C++ 类/结构和 C 结构之间的兼容性。
那是我的问题。我有虚拟方法,我非常希望在用 C++ 操作结构时保留它们。
让我们来看看这个玩具示例。它是在单个头文件中定义的与 C 和 C++ 兼容的结构。
mystr.h:
这可能并不完全漂亮,但可以用于示例。在实际场景中,C 和 C++ 变体可能位于不同的标头中,而 C++ 结构扩展了 POD 结构。无论实施如何,对齐问题仍然存在。
在此示例中,如果编写的 C 程序将 的实例传递mystr
给 C++ 函数,则 vtable 将干扰对齐:
测试.h:
测试.cpp:
主.c:
(假设这是因为 C++ 函数试图data
从结构分配内存的末尾之外读取)
启用这种 C-C++ 互操作性同时仍保留在 C++ 中使用虚函数的能力的最佳方法是什么?
c++ - 64 位机器上 vptr 的大小**是否必须为 64 位?
我很好奇为什么 vptr 的大小在 64 位机器上似乎需要 64 位,以及 C++ 是否真的需要它。
所有 vptr 需要做的就是指向 vtables,并且由于 vtables 不能占用太多内存并且可以组合在一起,32 位应该足以解决它们。
你的课程有多少个课程?1000?10000?他们平均有多少个虚函数?也许100?如果编译器+链接器连续放置所有 vtable,它们占用的空间不会超过几 MB。将具有 32 位索引的特定 vtable 寻址到“所有 vtable 的数组”中应该可以工作。
我之所以这么说,是因为某些带有虚函数的小类;有时我会看到一个只有 2 个单词 + vptr 的类的大量对象数组,而 64 位 vptr 对内存使用有重大影响。
c++ - 多继承中的c ++ vtable,指向thunk方法的指针
我读了这篇文章: https ://shaharmike.com/cpp/vtable-part2/
而且我不明白为什么在 vtable 中(在文章末尾)我们有这个指针:
0x400918 0x400820 非虚拟 thunk 到 Child::FatherFoo()
但不是直接指向方法 Child::FatherFoo() 的指针?
我假设 Child 的 vtable 与 Father 的 vtable 完全分开。
c++ - 找出 vptr 字段
我有几节课,我试图了解 vptr 和 vtable 在这种情况下是如何工作的。
我试图弄清楚运行以下实现后堆栈和堆应该如何:
据我了解,创建了 2 个 vptr:
- B::vpointer - 在堆栈上
- A::vpointer - 在堆上
它们是否具有相同的价值?(包含相同的地址?)这里有多少个 vtable?
c++ - 一个抽象虚函数的 vtable 中有多少条目?
我读到抽象类仍然可以有一个表。但我对它的 vtable 中有多少条目感到困惑。例如,如果我的抽象类是:
那么它的 vtable 中有多少条目?另外,我是否正确地说这个抽象类在其 vtable 中有 1 个条目?谢谢你的帮助。
c++ - vptr 上的数据竞争是否明确非法?
在进一步讨论之前,请注意:这纯粹是一个语言律师问题。我希望根据标准报价得到答案。我不是在寻找有关编写 C++ 代码的建议。请像我是编译器作者一样回答。
在构造仅具有独占子对象 (#) 的对象期间,尤其是那些仅具有非虚拟基类的对象(也具有仅命名一次的虚拟基类的对象),引用基类子对象的左值的动态类型“增加”:它会从基类的类型到构造函数运行的类的类型。
(#)当一个子对象恰好是另一个对象(可能是另一个子对象或完整对象)的直接子对象时,它是独占的。成员和非虚拟基地总是互斥的。
在销毁期间,类型会减少(直到该子对象的析构函数主体的末尾,子对象消失并且不再具有动态类型)。
[在构建具有共享基类子对象的对象期间(即在具有至少一个虚拟基的不同基子对象的类中),基子对象的动态类型可以暂时“消失”。我不想在这里讨论这样的课程。]
真正的问题是:如果在另一个线程中增加对象的动态类型会发生什么?
问题的标题是标准 C++ question,使用非标准术语 (vptr) 表示,这可能看起来自相矛盾。原因是:
- 没有要求根据 vptr 实现多态性,但它(几乎?)总是如此。对象中的一个(或多个)vptr 表示多态对象的动态类型。
- 数据竞争是根据对内存位置的读/写操作定义的。
- 标准文本通常使用“仅用于说明”的非标准元素来定义标准特征。(那么,为什么不使用 vptr “仅用于展示”?)
该标准没有将多态对象 (*) 的行为直接定义为动态类型的函数;该标准规定了在所谓的“生命周期”内(在构造函数完成之后)允许哪些表达式,在最派生类型的构造函数的主体内(完全相同的表达式允许具有相同的语义),也在基类子对象构造函数...
(*) 多态或动态对象的动态行为(**) 包括:多态对象的虚拟调用、派生到基本转换、向下转换 (static_cast
或dynamic_cast
) typeid
。
(**) 动态对象是其类使用 virtual 关键字的对象;由于这个原因,它的构造函数并不是微不足道的。
所以描述说:在某事完成之后,一旦某事开始,在其他事之前,等等,某个表达式是有效的并且会做某事。
构造和销毁的规范是在线程成为标准 C++ 的一部分之前编写的。那么线程标准化带来了什么变化呢?有一句话定义了线程行为(规范部分)[basic.life] /11:
在本小节中,“之前”和“之后”指的是“发生在之前”关系([intro.multithread])。
所以很明显,如果在构造函数调用的完成和对象的使用之间存在发生之前的关系,并且在对象的使用和析构函数的调用之前发生关系,则对象被视为完全构造的(如果它被调用)。
但是它没有说明在构造派生类期间会发生什么,在构造了基类子对象之后:显然,如果任何动态属性用于正在构造的多态对象,则存在竞争条件,但竞争条件并非非法。
[竞争条件是一种非确定性的情况,任何对互斥锁、条件变量、rwlocks 的有意义使用、信号量的多次使用、其他同步设备的多次使用以及原子原语的所有使用都会引入竞争条件,至少在原子对象的修改顺序级别。低级别的非确定性是否会导致不可预测的高级行为取决于原语的使用方式。]
然后标准草案继续说:
[ 注意:因此,如果在一个线程中构造的对象在没有充分同步的情况下从另一个线程引用,则会导致未定义的行为。——尾注]
“充分同步”在哪里定义?
缺乏“充分同步”是否相当于常规数据竞赛的道德等价物:vptr 上的数据竞赛,或者通俗地说,动态类型上的数据竞赛?
为简单起见,我希望将问题的范围限制为单一继承,至少作为第一步。(无论如何,该标准对具有多重继承的对象的构造感到非常困惑。)
这是语言律师问题,所以我不感兴趣:
- 是否建议使用正在另一个线程中构建的对象(可能不建议);
- 如何使用同步来可靠地修复该竞争条件;
- 编译器供应商是否希望支持这样的用例(他们可能不会也不会);
- 这是否可能在任何现实世界的实现中可靠地工作(它可能不会在当前实现的非平凡情况下可靠地工作)。
编辑:前面的例子没有说明问题,而是分散了注意力。它在聊天部分引起了非常有趣但完全不相关的讨论。
这是一个更简洁的示例,不会导致相同的问题:
使用消费者/生产者逻辑:
- 线程 A:
new Der2;
- 线程 B:
use_shared();
供参考,原始示例:
消费者/生产者逻辑:
- 线程 A:
new Der;
- 线程 B:
use_shared();
尚不清楚在构造函数this
执行期间是否可以被另一个线程使用Base
,这是一个有趣的问题,但与派生构造函数在另一个线程中运行时使用基类子对象的问题无关。
附加信息
作为参考,“激发”当前措辞的 DR(尽管这没有解释任何内容):