2012-08-01 45 views
1

我分析在我们的应用程序访问冲突发生,因为它试图调用一个对象,它的虚函数表点为0的虚拟功能,所以我想知道在对象的生命周期中的哪些点是虚拟函数表指针未设置或显式设置为零?当虚函数表设置为0

(我们使用Visual C++ 10作为编译器。)

+0

如果能够在代码中复制问题,解决问题可能会更容易。由于滥用正在建设中的对象,您可能有一个UB实例。 – 2012-08-01 09:33:42

+0

这感觉就像是错误的方法。首先通过内存调试器运行你的程序,然后弄清楚你是不是双重删除某些东西,或者沿着这些方向行事。 – 2012-08-01 09:47:25

+0

我会尽我所能,但不幸的是,这个问题在我们的开发系统上不会出现,所以我只有转储文件进行分析。 – fschoenm 2012-08-01 09:52:12

回答

2

V表指针将永远不会为0,而所述对象是处于有效状态。在施工过程中和破坏,而对象具有动态类型的抽象基类的,虚函数表将指向抽象基类虚函数表,其中包括纯虚函数,但V表指针本身仍然是非零的。

唯一一次虚表指针可以是零是施工前或破坏之后。

+0

那么我的类的最后一个析构函数是否明确地将vtable指针设置为零?那么我会假设我正在处理一个应该被删除的对象,但在内存中被覆盖之前,它仍然或多或少保持完好无损。 – fschoenm 2012-08-01 09:38:45

+0

它不需要(一旦对象完全被破坏,对状态没有要求),但这样做可以帮助捕获错误。替代方法是内存损坏。 – ecatmur 2012-08-01 10:18:18

+0

就是这样:对象已经被破坏,但是来自另一个线程,所以访问冲突受制于赛车条件。 – fschoenm 2012-08-03 18:55:42

1

如果虚函数表指针是真正的零,那么你可能已经使用了VC++的扩展,如:

class __declspec(novtable) Base { 
public: 
    Base(); 
    virtual void proc(); 
}; 

这里__declspec(novtable)告诉编译器的类并不需要一个虚函数表,因为没有虚函数会直到派生类安装了它自己的vtable。如果你在发生之前调用Base :: proc(),你可能会得到错误。

更可能的虚函数表本身是不为零,但作用在它插槽为零,由于函数是纯虚:

class Base { 
public: 
    virtual void proc() = 0; 
}; 

,然后有人把它称为反正这样的代码:

void Derived::proc() { 
    Base::proc(); 
    // Derived-specific stuff here. 
}; 

发生这种情况,因为衍生假设要调用基版本需要他们的覆盖,笔者虽然基本版本不存在。

无论哪种方式,一种方法寻找这将是停止所有的基类有心计,通常定义函数,看看调用它。例如:

class Base { 
public: 
    virtual void proc() { 
     assert(typeof(*this) != typeof(Base)); // Break-point here. 
    } 
}; 
+0

这两者都不是。调试器显式地将vtable指针显示为零,因此甚至不能显示单个条目。 – fschoenm 2012-08-01 12:57:32