是否有明确定义的方法来访问类的vtable?在visual studio中调试时我可以扩展这个'喜欢:this-> _ptr-> __ vfptr。但是这条路径似乎没有从代码中获得。
我需要这个用于自定义堆实现(嵌入式环境)的单元测试。
背景
我们有一个错误,在我们的自定义堆上分配的对象(除了特定大小的数组之外的任何东西)都没有按预期工作,直到我们想要添加一个具有虚函数的对象(它我们花了很长时间才意识到这种添加是问题的原因)。我们所犯的错误是将一个对象分配给内存,在分配之前没有对象被初始化。在编写代码时我们没有太多关注,因为它与其他所有代码一起工作并经过测试,我们认为它有效。这是一些示例代码:
int array_ptr[sizeof(SomeObject)];
*((SomeObject*) array_ptr) = SomeObject(); // Does only partially initialize the object!
一旦我们意识到这条线就是问题,那么也很清楚为什么会这样。
答案 0 :(得分:4)
啊哈,我现在明白了,评论中的澄清。
您在仅具有CFoo::operator=
的尺寸的原始内存上调用CFoo
。对于常见的实现,这确实不会设置vtable。这特定于C ++中的赋值如何工作。 C ++中的对象分配被定义为切片。如果您将Derived
对象分配给Base
课程,则需要拨打Base::operator=(Base const& src)
。这仅复制Derived
对象的Base子对象。
C ++选择此模型的原因是因为这意味着Base
对象在为其分配Derived
值时不会改变大小,显而易见的是丢失额外信息的代价
实际效果是C ++对象在构造后不会改变类型。实际上,这意味着构造函数可以修复类型和vtable 。分配操作员不会碰它。
因此,通过在原始内存上调用赋值运算符,您将获得未定义行为,特别是未初始化(垃圾)vtable。你不能指望它全是零。此外,在具有多个虚拟继承的更复杂情况下,还有其他数据字段可用于查找各种子对象。那些也将是未初始化的。请注意,这些附加数据字段可能包含绝对指针。 memcpy
这样的对象,您可以回到原始的子对象。
CFoo
对象,所有访问内存的尝试都是未定义行为。
解决方案是展示位置new
。这是将原始记忆转化为物体的神奇咒语。它可以使用任何构造函数,包括移动构造函数和复制构造函数,但是(除了异常)将为您提供一个有效的对象,具有适当的多态行为。
答案 1 :(得分:0)
好的,所以从MSalters和其他评论者那里学习,我知道没有直接的方法来阅读vtable指针。但是,我提出了一个足以满足我需求的解决方案(即测试vtable指针是否已正确初始化)。所以这里是代码(注意我假设我得到的是vtable指针sizeof(size_t)== sizeof(EmptyClassWithOneVirtualFunction)):
class EmptyClassWithOneVirtualFunction
{
virtual void testFunction() {}
};
void test_staticNew_object_vtable()
{
EmptyClassWithOneVirtualFunction correctObject;
EmptyClassWithOneVirtualFunction* object = mem::static_new<EmptyClassWithOneVirtualFunction>();
size_t* correctObjectVtablePtr = ( (size_t*) &correctObject );
size_t* objectVtablePtr = ( (size_t*) object );
TS_ASSERT_EQUALS( *objectVtablePtr, *correctObjectVtablePtr );
}
应该指出的是,这是在没有优化的情况下以调试模式构建的测试代码。为了能够捕捉这个错误,即使在这不完全&#34;安全&#34;方式对我来说比跳过这样做更有价值,因为没有正确的方法去做。