虚拟方法混乱,我怎样才能找到导致这种情况的原因?

时间:2010-01-07 21:31:12

标签: c++ debugging visual-studio-2005 virtual-method

我的一位同事今天遇到了一些C ++代码的问题。他正在调试对象虚拟方法的怪异行为。每当方法执行时(在调试,Visual Studio 2005下),一切都出错了,调试器不会介入该方法,而是在对象的析构函数中!此外,对象的虚拟表,只列出了它的析构函数,没有其他方法。

之前我没有看到过这种行为,并且打印了运行时错误,说明了ESP寄存器。我希望我能给你正确的错误信息,但我现在不记得了。

无论如何,你们有没有遇到过这样的人?什么可能导致这种行为?怎么解决?我们尝试多次重建项目,重新启动IDE,没有任何帮助。我们还在该方法调用之前使用了_CrtCheckMemory函数来确保内存处于良好状态,并返回true(这意味着确定)。我没有更多的想法。你呢?

5 个答案:

答案 0 :(得分:2)

我以前见过。通常它会发生,因为我在调试模式下使用Release内置的.LIB文件中的类。其他人可能已经看到了一个更好的例子,我会回答他们的答案。

答案 1 :(得分:1)

也许您使用需要static_cast<>的C风格演员?每当涉及多重继承时,这可能会导致您报告的错误类型,例如:

class Base1 {};
class Base2 {};
class Derived : public Base1, public Base2 {};

Derived *d = new Derived;
Base2* b2_1 = (Base2*)d; // wrong!
Base2* b2_2 = static_cast<Base2*>(d); // correct
assert( b2_1 == b2_2 ); // assertion may fail, because b2_1 != b2_2

注意,情况可能并非总是如此,这取决于编译器和所涉及的所有类的声明(当所有类都有虚拟方法时可能会发生,但我手头没有确切的规则)。

OR:代码的一个完全不同的部分是疯狂的并且正在覆盖内存。尝试隔离错误并检查是否仍然发生。 CrtCheckMemory只会发现一些覆盖内存的情况(例如,当您写入特殊标记的堆管理位置时)。

答案 2 :(得分:1)

如果您使用错误数量的参数调用函数,则很容易导致垃圾堆栈被丢弃并产生未定义的行为。我似乎记得使用MFC时的某些错误很容易导致这种情况,例如,如果您使用调度宏将消息指向一个没有正确数量或类型参数的方法(我似乎记得那些函数指针没有强烈检查类型)。自从我上次遇到这个特殊问题以来已经十年了,所以我的记忆很模糊。

答案 3 :(得分:1)

  

ESP的值未在函数调用中正确保存。

这种行为通常表示调用代码使用与创建所讨论的特定类的代码不同的类或函数定义进行编译。

是否可能存在正在加载的组件dll的不同版本而不是新构建的组件?如果您在构建后步骤中复制内容,或者在执行LoadLibrary或等效操作之前从其他目录运行或更改其dll搜索路径,则会发生这种情况。

我经常在复杂的项目中遇到过这种情况,在这些项目中,类定义被更改为添加,删除或更改虚函数的签名,然后进行增量构建,而不是所有需要重新编译的代码实际上都是重新编译。从理论上讲,如果程序的某些部分覆盖了某些多态对象的vptr或vtable,可能会发生这种情况,但我总是发现错误的部分构建更可能是原因。

这可能是“用户错误”,开发人员故意告诉编译器只在其他人应该重建时构建一个项目,或者在没有正确设置依赖关系的解决方案中可能有多个解决方案或多个项目。

即使解决方案中的项目正确链接,Visual Studio也偶尔会出现问题并且无法使生成的依赖项正确无误。这种情况发生的频率低于Visual Studios的责任。

从源代码中删除所有中间构建文件并重建所有内容通常可以解决问题。显然,对于非常大的项目,这可能是一个严重的惩罚。

答案 4 :(得分:1)

无论如何,这是猜测,这是我的一个:

你的筹码混乱,_CrtCheckMemory没有检查。至于堆栈被破坏的原因:

  • 好旧堆栈溢出
  • 调用约定不匹配,已经提到过(我不知道,就像将错误的调用约定中的回调传递给WinAPI函数;你链接的是什么静态或动态库?)
  • printf("%d");
  • 这样的行