Reputation: 19
My program has been written using classes from the SDL library.
I have the following class:
class s_group
{
private:
SDL_Surface* image;
unsigned int* F_total;
float* F_length;
SDL_Rect** F;
float* F_current;
unsigned int S_total;
unsigned int S_current;
public:
s_group(void);
virtual ~s_group(void);
bool setup( const char* filename, unsigned int s );
//other member functions
};
Private member pointers each store the location of memory declared on the heap, as allocated by the member function setup
.
bool s_group::setup( const char* filename, unsigned int s )
{
s_group::~s_group();//delete already allocated heap memory
if(!load_file(image, filename))
{
image = NULL;
return false;
}
S_total = s;
F = new SDL_Rect*[S_total];
F_total = new unsigned int[S_total];
F_length = new float[S_total];
F_current = new float[S_total];
for(unsigned int index = 0; index < S_total; ++index)
{
F[index] = NULL;
F_total[index] = 0;
F_length[index] = 0.f;
F_current[index] = 0.f;
}
//loop for each array slot and set values of data
return true;
}
Within a large function I create an object of this class on the heap, storing its address in an s_group
pointer named sparkle
.
s_group* sparkle = new s_group;
sparkle->setup("sparkle_final.png", 1 );
On completion of the function I call delete
to reallocate the heap memory. Removing this line solves the problem, however there would then be a memory leak.
delete sparkle;
sparkle = NULL;
This will call the destructor of the class which is where I believe the error occurs due to an internal use of the delete
operator.
s_group::~s_group(void)
{
SDL_FreeSurface(image);
image = NULL;
for(unsigned int s = 0; s < S_total; ++s)
{
for(unsigned int f = 0; f < F_total[s]; ++f)
{
F[s][f].x = 0;
F[s][f].y = 0;
F[s][f].w = 0;
F[s][f].h = 0;
}
delete[] F[s];
F[s] = NULL;
}
delete[] F;
F = NULL;
delete[] F_total;
F_total = NULL;
delete[] F_length;
F_length = NULL;
delete[] F_current;
F_current = NULL;
S_total = 0;
S_current = 0;
}
On reaching the delete operator, a dialog box appears stating:
Windows has triggered a breakpoint in Program.exe. This may be due to a corruption of the heap, which indicates a bug in Program.exe or any of the DLLs it has loaded.
How do I delete
this object without causing the heap corruption?
Upvotes: 1
Views: 1638
Reputation: 19
Since posting this question I have located the source of the error and solved the issue. In a separate section of code which set the data values for the dynamic 2D array the loop validation was incorrect.
for( unsigned int index = 0; index <= F_total[ S_current ]; ++index ) {
//set data values for each slot in the array
F[ S_current ][ index ].x = 0; etc...
}
As can be seen the loop will clearly attempt to modify a location equal to the size of the created array. Noting of course that arrays begin at index 0, so the final slot will be at size - 1. Something very silly that I missed when writing the code. Actual loop:
for( unsigned int index = 0; index < F_total[ S_current ]; ++index ) {
//set data values for each slot in the array
F[ S_current ][ index ].x = 0; etc...
}
A message for anyone attempting their own memory management:
Upvotes: 0
Reputation: 23500
I'm unable to compile your code but here goes..
The first thing I noticed was that you called your destructor.. You don't want to do that! Instead, create a release function and call that.
The next thing I noticed is that there is no FRAME
variable within the class itself.. so this line:
FRAME = new SDL_Rect*[S_total];
is going to cause a compilation error and your destructor uses FRAME
but no such variable exists. I think you meant to change it to F
because if not, then this line:
F[index] = NULL;
is undefined behaviour since F is uninitialized..
Also, you never initialized each index of FRAME
and so accessing it in the destructor like:
FRAME[s][f].x = 0;
is a no-no.
Again, you call
delete[] F;
F = NULL;
but F has no memory allocated and is uninitialized.
Thus with all the patches I think:
class s_group
{
private:
SDL_Surface* image;
unsigned int* F_total;
float* F_length;
SDL_Rect** FRAME;
float* F_current;
unsigned int S_total;
unsigned int S_current;
void Release();
public:
s_group(void);
virtual ~s_group(void);
bool setup(const char* filename, unsigned int s);
//other member functions
};
bool s_group::setup(const char* filename, unsigned int s)
{
Release();//delete already allocated heap memory
if(!load_file(image, filename))
{
image = NULL;
return false;
}
S_total = s;
FRAME = new SDL_Rect*[S_total];
F_total = new unsigned int[S_total];
F_length = new float[S_total];
F_current = new float[S_total];
for(unsigned int index = 0; index < S_total; ++index)
{
FRAME[index] = NULL;
F_total[index] = 0;
F_length[index] = 0.f;
F_current[index] = 0.f;
}
//loop for each array slot and set values of data
return true;
}
void s_group::Release()
{
SDL_FreeSurface(image);
image = NULL;
for(unsigned int s = 0; s < S_total; ++s)
{
for(unsigned int f = 0; f < F_total[s]; ++f)
{
if (FRAME[s])
{
FRAME[s][f].x = 0;
FRAME[s][f].y = 0;
FRAME[s][f].w = 0;
FRAME[s][f].h = 0;
}
}
delete[] FRAME[s];
FRAME[s] = NULL;
}
delete[] FRAME;
FRAME = NULL;
delete[] F_total;
F_total = NULL;
delete[] F_length;
F_length = NULL;
delete[] F_current;
F_current = NULL;
S_total = 0;
S_current = 0;
}
s_group::~s_group(void)
{
Release();
}
should do it.. Just don't forget to allocate memory for FRAME[index]
I wasn't sure how much or what you wanted to allocate so I changed the Release
function to check if FRAME[index]
is valid with an if-statement
I would strongly advise that you use some SmartPointers
and forget about handling every single memory allocation yourself..
Upvotes: 0
Reputation: 3049
From effective C++ Scott Meyers
You shouldn't call virtual functions during construction or destruction, because the calls won't do what you think, and if they did, you'd still be unhappy. If you're a recovering Java or C# programmer, pay close attention to this Item, because this is a place where those languages zig, while C++ zags.
Upvotes: 2