可以在堆栈上创建对象之前将其展开吗?

时间:2010-02-24 13:20:46

标签: c++ debugging c++builder access-violation

我们已经调试了几天的奇怪案例,并且有点孤立了这个bug,但它仍然没有任何意义。也许这里的任何人都可以给我一些关于发生了什么的线索。

问题是代码的一部分发生访问冲突。

基本上我们有类似的东西:

void aclass::somefunc() {
  try {
    erroneous_member_function(*someptr);
  } 
  catch (AnException) {
  }
}

void aclass::erroneous_member_function(const SomeObject& ref) {
  // { //<--scope here error goes away
  LargeObject obj = Singleton()->Object.someLargeObj; //<-remove this error goes away

  //DummyDestruct dummy1//<-- this is not destroyed before the unreachable

  throw AnException();

  // } //<--end scope here error goes away 

  UnreachableClass unreachable; //<- remove this, and the error goes away

  DummyDestruct dummy2; //<- destructor of this object is called! 
}

虽然在调试器中它实际上看起来它正在破坏UnreachableClass,但是当我插入DummyDestruct对象时,在调用奇怪的析构函数之前这不会被破坏。所以看起来大型对象的破坏似乎不会出错。

这一切都在生产代码的中间,很难将它分离成一个小例子。

我的问题是,有没有人知道是什么导致了这种情况,以及发生了什么?我有一个功能齐全的调试器(Embarcadero RAD工作室),但现在我不知道如何处理它。

有人可以就如何继续提供一些建议吗?

更新

我在throw子句下放置了一个DummyDestruct对象,并在析构函数中放置了一个断点。输入此对象的析构函数(并且它只有我们在这段代码中)。

5 个答案:

答案 0 :(得分:1)

根据您提供的信息,如果一切都如您所述,唯一可能的答案是编译器/优化器中的错误。只需添加一个注释的额外范围(再次,如果一切都与您所说的完全一样)。

答案 1 :(得分:1)

这样的东西有时会发生,因为通过未初始化的指针写入,超出数组访问等等。引起错误的点可能会从它显示的地方完全删除。但是,根据您描述的症状,它似乎已在此功能中进行了本地化。 LargeObject的复制构造函数可能行为不端吗?是否使用了ref?也许somePtr并未指向有效的SomeObjectSingleton()是否返回指向有效对象的指针? 编译器错误也是可能的,特别是在启用积极优化的情况下。我会尝试重新创建没有优化的错误。

答案 2 :(得分:1)

时间练习我的心灵感应调试技巧:

我最好的猜测是你的应用程序有一个堆栈损坏错误。这可以在调用堆栈上写入垃圾,这意味着调试器在您中断时错误地报告了该函数,并且它实际上并不在析构函数中。要么你或者你错误地解释了调试器的信息而对象真的被正确破坏了,但是你不知道为什么!

如果堆栈损坏是这种情况,那么你将很难找出根本原因。这就是为什么在整个程序中实现大量诊断(例如断言)非常重要的原因,这样你就可以在发生堆栈时发现堆栈损坏,而不是陷入其奇怪的副作用。

答案 3 :(得分:0)

这可能是一个真正的远景,但无论如何我都会把它放在那里......

你说你用的是borland - 什么版本?你说你看到字符串中的错误 - STL?你的项目中是否包含winsock2?

我问的原因是我在使用borland 6(2002)和winsock时遇到了问题 - 标题似乎搞乱了结构包装并且意味着不同的翻译单元对std :: string的内存布局有不同的看法,取决于翻译单元包含的标题,具有可预测的灾难性结果。

答案 4 :(得分:0)

这是另一个疯狂的猜测,因为你提到了字符串。我知道至少有一个实现,其中(STL)字符串复制以惰性方式完成(即,在进行更改之前不会对字符串内容进行实际复制;通过简单地使用目标字符串对象来完成“复制”指向与源相同的缓冲区。在该特定实现(GNU)中,存在一个错误,即过度复制导致引用计数器(在假定复制之后有多少对象使用相同的实际字符串内存)翻转为0,从而导致各种恶作剧。我自己没有遇到这个错误,但有人告诉过它。 (我这样说是因为人们会认为参考计数器是一个32位的数字,并且这种情况的可能性非常小,至少可以说,所以我可能没有正确地描述这个问题。)