bds 2006 C隐藏的内存管理器冲突(class new / delete [] vs. AnsiString)

时间:2013-07-17 11:03:39

标签: memory-management struct c++builder ansistring c++builder-2006

我正在使用 BDS 2006 Turbo C ++ 很长一段时间,我的一些大项目( CAD / CAM,3D gfx引擎和Astronomic计算)偶尔抛出一个例外(例如,在24/7重负荷使用的3-12个月中一次)。经过大量调试后我发现了这个:

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

此代码通常位于模板中,其中_s也可以是类delete[]此代码应该正常工作,但delete[]对结构不起作用(类看起来没问题)。没有异常被抛出,内存被释放,但它以某种方式损坏了内存管理器分配表,在此之后任何新的分配都可能是错误的(新的可以创建具有已分配空间的重叠分配,甚至是未分配的空间,因此偶尔会出现异常)

我发现如果我将空的析构函数添加到_s,而不是突然看起来一切正常

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中包含一些有用的数据,之后是通过添加行创建的txt字符串,因此必须重新分配txt几次,有时dat数据被txt覆盖(即使它们没有重叠,我重新分配AnsiString所需的临时txtdat重叠

所以我的问题是:

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

    • 经过大量调试(在发布问题2之后),我发现AnsiString不会导致问题。它们仅在使用时发生。真正的问题可能是在 OpenGL 客户端之间切换。我有打开/保存对话框,带有矢量图形预览。如果我为这些 VCL 子窗口禁用 OpenGL ,则AnsiString内存管理错误将完全消失。我不支持问题是什么( MFC / VCL 窗口之间不兼容,或者更可能是我在切换上下文时犯了一些错误,将进一步调查)。关注 OpenGL 窗口是:
    • 主要 VCL 表单+ {strong> OpenGL 在Canvas客户区内
    • 主要 MFC的孩子打开/保存对话框+停靠预览 VCL 表单+ {strong> OpenGL Canvas客户区
  3. P.S。

    1. 这些错误取决于new/delete/delete[]次使用的数量,而不是分配的尺寸
    2. code1和code2错误都是重复的(例如,有一个解析器来加载复杂的ini文件,如果没有更改ini,则错误发生在同一行)
    3. 我只在大型项目(普通源代码> 1MB)上检测到这些错误,并结合使用AnsiString和模板与内部动态分配,但可能它们也在更简单的项目中但很少发生我想念它。
    4. 受感染的项目规格:
      • win32 noinstall standalone(使用 Win7sp1 x64 ,但 XPsp3 x32 表现相同)
      • 如果使用 GDI OpenGl / GLSL
      • 不会计量 如果使用设备驱动程序 DLL ,则
      • 不计量
      • OCX ,或非标准 VCL 组件
      • DirectX
      • 1字节对齐编译/链接
      • 不要使用 RTL ,包或框架(独立)
    5. 抱歉英语/语法不好...... 任何帮助/结论/建议表示赞赏。

1 个答案:

答案 0 :(得分:2)

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

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

此后内存管理不可靠。 ('new'可以分配已经分配的空间)

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

//---------------------------------------------------------------------------
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()中,类a的析构函数被称为两次。一次为真正的a和一次为它的副本,因为我忘了创建构造函数

test::test(test &x);

[Edit1]进一步升级代码

好的我已经改进了类和struct甚至模板的初始化代码,以修复更多的bug案例。将此代码添加到任何结构/类/模板,如果需要,添加功能

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内部使用动态分配时才需要最后一个运算符(如果没有使用分配,则可以保留原样)

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

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

如果您需要调试内存分配,请查看traceback a pointer in c++ code mmap ...