问题
I am using BDS 2006 Turbo C++ for a long time now and some of my bigger projects (CAD/CAM,3D gfx engines and Astronomic computations) occasionally throw an exception (for example once in 3-12 months of 24/7 heavy duty usage). After extensive debugging I found this:
//code1:
struct _s { int i; } // any struct
_s *s=new _s[1024]; // dynamic allocation
delete[] s; // free up memory
this code is usually inside template where _s
can be also class therefore delete[]
this code should work properly, but the delete[]
does not work properly for structs (classes looks OK). No exceptions is thrown, the memory is freed, but it somehow damages the memory manager allocation tables and after this any new allocation can be wrong (new can create overlapped allocations with already allocated space or even unallocated space hence the occasional exceptions)
I have found that if I add empty destructor to _s
than suddenly seems everything OK
struct _s { int i; ~_s(){}; }
Well now comes the weird part. After I update this to my projects I have found that AnsiString
class has also bad reallocations. For example:
//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;
In this code dat
contains some useful data, then later is some txt
string created by adding lines so the txt
must be reallocated few times and sometimes the dat
data is overwritten by txt
(even if they are not overlapped, I thing the temp AnsiString
needed to reallocate txt
is overlapped with dat
)
So my questions are:
- Am I doing something wrong in code1, code2 ?
Is there any way to avoid
AnsiString
(re)allocation errors ? (but still using it)- After extensive debugging (after posting question 2) I have found that
AnsiString
do not cause problems. They only occur while using them. The real problem is probably in switching between OpenGL clients. I have Open/Save dialogs with preview for vector graphics. If I disable OpenGL usage for these VCL sub-windows thanAnsiString
memory management errors disappears completely. I am not shore what is the problem (incompatibility between MFC/VCL windows or more likely I made some mistake in switching contexts, will further investigate). Concern OpenGL windows are: - main VCL Form + OpenGL inside
Canvas
client area - child of main MFC Open/Save dialog + docked preview VCL Form + OpenGL inside
Canvas
client area
- After extensive debugging (after posting question 2) I have found that
P.S.
- these errors depend on number of
new/delete/delete[]
usages not on the allocated sizes - both code1 and code2 errors are repetitive (for example have a parser to load complex ini file and the error occurs on the same line if the ini is not changed)
- I detect these errors only on big projects (plain source code > 1MB) with combined usage of
AnsiString
and templates with internal dynamic allocations, but is possible that they are also in simpler projects but occurs so rarely that I miss it. - Infected projects specs:
- win32 noinstall standalone (using Win7sp1 x64 but on XPsp3 x32 behaves the same)
- does not meter if use GDI or OpenGl/GLSL
- does not meter if use device driver DLLs or not
- no OCX,or nonstandard VCL component
- no DirectX
- 1 Byte aligned compilation/link
- do not use RTL,packages or frameworks (standalone)
Sorry for bad English/grammar ... any help / conclusion / suggestion appreciated.
回答1:
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:
- Too many initializers error for a simple array in bcc32
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...
来源:https://stackoverflow.com/questions/17698102/bds-2006-c-hidden-memory-manager-conflicts-class-new-delete-vs-ansistring