2

我使用BDS 2006 Turbo C++已经很长时间了,我的一些大型项目(CAD/CAM、3D gfx 引擎和天文计算)偶尔会抛出异常(例如,在 3-12 个月的 24/7 重型使用中) )。经过大量调试后,我发现:

//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认为重新分配所需的 temptxt与重叠dat

所以我的问题是:

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

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

附言

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

抱歉英语/语法不好......任何帮助/结论/建议表示赞赏。

4

1 回答 1

2

After extensive debugging i finely isolated the problem. Memory management of bds2006 Turbo C++ became corrupt after you try to call any delete for already deleted pointer. for example:

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

After this is memory management not reliable. ('new' can allocate already allocated space)

Of course deletion of the same pointer twice is bug on programmers side, but i have found the real cause of all my problems which generates this problem (without any obvious bug in source code) see this code:

//---------------------------------------------------------------------------
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();
    }
//---------------------------------------------------------------------------

In function get() is called destructor for class a twice. Once for real a and once for its copy because I forget to create constructor

test::test(test &x);

[Edit1] further upgrades of code

OK I have refined the initialization code for both class and struct even templates to fix even more bug-cases. Add this code to any struct/class/template and if needed than add functionality

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 is the struct/class name
  • the last operator is needed only if T uses dynamic allocations inside it if no allocations are used you can leave it as is

This also resolves other compiler issues like this:

If anyone have similar problems hope this helps.

Also look at traceback a pointer in c++ code mmap if you need to debug your memory allocations...

于 2013-08-02T12:00:51.300 回答