BDS 2006 C隐藏内存pipe理器冲突(类新/删除与AnsiString)

我现在使用BDS 2006 Turbo C ++很长一段时间了,我的一些更大的项目( CAD / CAM,3D gfx引擎和天文计算)偶尔会抛出一个exception(例如一次在3到12个月内每天24/7重用)。 广泛的debugging后,我发现这一点:

//code1: struct _s { int i; } // any struct _s *s=new _s[1024]; // dynamic allocation delete[] s; // free up memory 

这个代码通常在模板里面,因为_s也可以是类,所以delete[]这个代码应该可以正常工作,但是delete[]对于结构(类看起来不错)不能正常工作。 没有任何例外,内存被释放,但它以某种方式损害内存pipe理器分配表,并在此之后,任何新的分配可能是错误的(新可以创build重叠的分配已经分配的空间,甚至未分配的空间,因此偶尔的例外)

我发现,如果我添加空的析构函数比突然似乎一切OK

 struct _s { int i; ~_s(){}; } 

那么现在是怪异的一部分。 在我更新这个项目之后,我发现AnsiString类也有不好的重新分配。 例如:

 //code2: int i; _s *dat=new _s[1024]; AnsiString txt=""; // setting of dat for (i=0;i<1024;i++) txt+="bla bla bla\r\n"; // usage of dat delete[] dat; 

在这个代码中, dat包含一些有用的数据,然后是一些通过添加行创build的txtstring,所以txt必须重新分配几次,有时dattxt覆盖(即使它们没有重叠,我需要temp需要AnsiString重新分配txtdat重叠)

所以我的问题是:

  1. 我在code1,code2中做错了什么?
  2. 有没有办法避免AnsiString (重新)分配错误? (但仍然使用它)

    • 经过广泛的debugging(在发布问题2之后),我发现AnsiString不会导致问题。 只有在使用它们时才会发生。 真正的问题可能是在OpenGL客户端之间切换。 我有打开/保存对话框预览vectorgraphics。 如果我禁用这些VCL子窗口的OpenGL使用比AnsiString内存pipe理错误完全消失。 我不是支持什么问题( MFC / VCL窗口之间的不兼容或更可能我在切换上下文中犯了一些错误,将进一步调查)。 关注OpenGL窗口是:
    • 主要的VCL Form + OpenGLCanvas客户区内
    • 主要的MFC子项打开/保存对话框停靠在Canvas客户区内的VCL Form + OpenGL

PS

  1. 这些错误取决于new/delete/delete[]用法的数量而不是分配的大小
  2. code1和code2错误都是重复的(例如,有一个parsing器来加载复杂的ini文件,如果ini没有改变,错误发生在同一行)
  3. 我只在大型项目(普通的源代码> 1MB)上检测到这些错误,结合使用了AnsiString和带有内部dynamic分配的模板,但是它们也可能在简单的项目中,但是很less发生,所以我错过了它。
  4. 受感染的项目规格:
    • win32 noinstall standalone(使用Win7sp1 x64,但在XPsp3 x32上performance相同)
    • 如果使用GDIOpenGl / GLSL ,则不计费
    • 如果使用设备驱动程序DLL ,则不测量
    • 没有OCX或非标准的VCL组件
    • 没有DirectX
    • 1字节alignment的编译/链接
    • 不要使用RTL ,包或框架(独立的)

对不起英语/语法错误…任何帮助/结论/build议表示赞赏。

经过广泛的debugging,我很好地隔离了这个问题。 尝试调用已删除的指针的任何删除后,bds2006 Turbo C ++的内存pipe理已损坏。 例如:

 BYTE *dat=new BYTE[10],*tmp=dat; delete[] dat; delete[] tmp; 

这之后内存pipe理就不可靠了。 (“新”可以分配已经分配的空间)

当然两次删除同一个指针是程序员方面的错误,但是我发现了所有产生这个问题的真正原因(源代码中没有任何明显的错误),请参阅以下代码:

 //--------------------------------------------------------------------------- class test { public: int siz; BYTE *dat; test() { siz=10; dat=new BYTE[siz]; } ~test() { delete[] dat; // <- add breakpoint here siz=0; dat=NULL; } test& operator = (const test& x) { int i; for (i=0;i<siz;i++) if (i<x.siz) dat[i]=x.dat[i]; for ( ;i<siz;i++) dat[i]=0; return *this; } }; //--------------------------------------------------------------------------- test get() { test a; return a; // here call a.~test(); } // here second call a.~test(); //--------------------------------------------------------------------------- void main() { get(); } //--------------------------------------------------------------------------- 

在函数中get()被称为类的析构函数两次。 一次真正的一次,因为我忘了创build构造函数

 test::test(test &x); 

[Edit1]代码的进一步升级

好的,我已经改进了类和结构甚至模板的初始化代码,以修复更多的错误情况。 将此代码添加到任何结构/类/模板,如果需要,则可以添加function

 T() {} T(T& a) { *this=a; } ~T() {} T* operator = (const T *a) { *this=*a; return this; } //T* operator = (const T &a) { ...copy... return this; } 
  • T是结构/类名称
  • 只有当T使用dynamic分配时才需要最后一个运算符,如果没有使用分配,可以保持原样

这也解决了这样的其他编译器问题:

  • bcc32中一个简单数组的初始化错误太多

如果有人有类似的问题,希望这有助于。

如果你需要debugging你的内存分配,也可以在c ++代码mmap中追踪一个指针 。