I have a function using a 2D array and I want to copy data from one array to another and I used a tmp array, but valgrind kept on saying I have memory leak. I can't figure out why. The following is part of a function.
// valgrind gave me error as operator new[] (unsigned long) for the following line
T** temp_pointer = new T*[rows];
for (int i=0; i < rows; i++) {
temp_pointer[i] = new T[columns];
}
for (int i =0; i< rows; i++) {
for (int j =0; j < (columns-3); j++) {
temp_pointer[i][j] = Arry[i][j];
}
temp_pointer[i][columns -3 ] = myvalue1;
temp_pointer[i][columns-2] = myvalue2;
temp_pointer[i][columns-1] = myvalue3;
}
for ( int i =0; i< rows; i++)
delete [] Arry[i];
delete [] Arry;
Arry= temp_pointer;
I also have a destructor which recursively delete the Arry pointers. Arry is private member of a template class.
I just could not figure out why it was a memory leak. Am I supposed to recursively delete temp_pointer ?? (I tried and it didn't work)
I just didn't know where did it leak?
It is not entirely clear why valgrind claims that the memory is being leaked, but you clearly have an out of bound access in your loop.
temp_pointer[i][columns] = myvalue;
The index of the last element of an array is not its size, it is (size-1). Writing into a location outside of the array's bound could clobber the memory allocator's housekeeping information and cause valgrind to complain.
Related
I'm trying to delete my 2D array, but I consistently get errors when I try to delete it, we have to work backwards so I delete the elements first, then the column array, then the row array. here is my code for the constructor in my class, MyMatrix:
private:
int m; //rows
int **ptr; //ptr to first dimension
int n; // columns
public:
MyMatrix() //constructor
{
m = 0;
n = 0;
ptr = new int*[m];
int *length_arr = new int[m];
for (int i = 0; i <= m-1; i++)
{
*(ptr+i) = new int[n];
*(length_arr+i) = n;
}
}
and my destructor looks like this:
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
the error I'm getting is:
assg7(2677,0x100de3d40) malloc: *** error for object 0x12d606804: pointer being freed was not allocated
I've wracked my brain for where I can fix this, for context, I'm doing an assignment with operator overloading. I specifically need a delete function to work properly for my = assignment overloading since I want to delete and again reallocate memory to equate two matrices, but the terminal is showing malloc errors and is thus not equating the matrices.
for additional info here is my = overloading code:
void operator = (const MyMatrix &obj)
{
if(n == obj.n && m == obj.m)
{
//for loop to equate elements in this-> to the elements of the passed object
}
else
{
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
// the code for assigning new memory according to the passed objects rows and colums goes here
//then for loop to equate elements in this-> to the elements of the passed object
}
}
thanks.
You have two "levels" of new, so three "levels" of delete can't be right.
Spell out your deletion loop, using indexing instead of pointer arithmetic:
First iteration:
delete ptr[0]+0;
delete ptr[0]+1;
...
delete ptr[0]+n-1;
delete [] ptr[0];
Second iteration:
delete ptr[1]+0;
delete ptr[1]+1;
...
delete ptr[1]+n-1;
delete [] ptr[1];
You're passing to delete a pointer to the first element of ptr[0], a pointer to the second element of ptr[0], a pointer to the third element of ptr[0], ...
But the things you allocated were ptr[0], ptr[1], ... ptr[m-1], not their individual elements.
Remove the innermost deletion loop.
(And don't mess around with pointer arithmetic when you can use indexing.)
I don't know how you would want to allocate memory space by m length if it is set to 0 by default.
To me it looks like you set m = 0 and then try to allocate by 0 length or how do you control the length of your dimensions?
Maybe edit your constructor to:
MyMatrix(int m, int n)
{
this->m = m;
this->n = n;
...
In my code, I have a 2D array of pointers to my data:
Data***
The reason I'm not using array notation is because the size is not determined at compile time.
So, somewhere in my code I allocate all the necessary space:
arr = new Data **[xVals];
for (int i = 0; i < xVals; i++)
{
arr[i] = new Data *[yVals];
for (int j = 0; j < yVals; j++)
{
arr[i][j] = nullptr;
}
}
And then fill the array with my proper pointers some time later on.
Furthermore, the pointer also gets stored in a std::vector:
for(...) {
for(...) {
// Conditional statement; not the whole array gets filled, some parts stay nullptr
...
arr[xCoord][yCoord] = new Data(...);
myVector.push_back(arr[xCoord][yCoord]);
}
}
... // Do some other stuff that takes advantage of the spatial properties of the 2D array
Once I'm done using the 2D array, I want to delete it, but NOT delete the Data-pointers themselves, since they are now stored in my vector.
I've been trying the following:
for (int i = 0; i < xVals; i++)
{
// Delete all "column" arrays
delete[] arr[i];
}
// Delete
delete[] arr;
However, I get a corrupted heap error CRT detected that the application wrote to memory after end of heap buffer, so I'm not sure what exactly I did wrong there. How do I delete a 2D array without deleting the data it held?
So I'm trying to create a function that "resizes" a member array to a new size passed as an argument. By "resize", I mean that it should set the member array to a new array with the new size, copy over the elements from the old array, and then deallocate the memory associated with the old array. Here's what I have so far:
void MemoryTest::resize(unsigned int new_size) {
if (size == new_size)
return;
int* oldPtr = elements;
elements = new int[new_size + 1];
for (int i = 0; i < (new_size < size) ? new_size : size; i++)
elements[i] = oldPtr[i];
elements[new_size] = '\0';
if (size > new_size)
size = new_size;
delete[] oldPtr; // Deallocate old elements array
}
elements is a private member int* initialized to NULL.
However, when it begins the for loop, the program hangs for awhile before giving an Access Violation for the elements[i] = oldPtr[i] line. Someone please correct me if I'm wrong (which I probably am), but my understanding is that oldPtr should be a pointer pointing to the same initial point as elements. Then, I set elements equal to a new array, so the two are now pointing to two different things. Then I iterate through elements, setting each item equal to its counterpart in the old array.
Also, while I would normally use a vector to avoid situations like this, I'm trying to become more familiar with pointers and memory allocation in C++.
Thanks in advance!
for (int i = 0; i < (new_size < size) ? new_size : size; i++)
should read
for (int i = 0; (i < (new_size < size)) ? new_size : size; i++)
So, for (int i = 0; i < ((new_size < size) ? new_size : size); i++) should correct your code.
My question arises from this answer.
In the comments he mentions that I should delete the allocated dynamic 2D array in the reverse order.
However I did not understand much why this should be done. Here is the code:
//intialising array
int size = 10000;
double **array = new double[size];
for(int i = 0; i < size; i++)
array[i] = new double[size];
//conventional de-initialise
for(int i = 0; i < size; i++)
delete[] array[i];
delete[] array;
//reverse de-initialise
for(int i = size - 1; size >= 0; i--)//notice reverse order here
delete[] array[i];
delete[] array;
So my question is, is there any significant difference between the 2 methods of de-allocating a 2D array?
In your example there's no difference - you create 100K pointers, and then allocate memory for each. It doesn't matter how you allocate/deallocate memory and assign it to pointers array.
However your question is about why reverse deallocation was in another post, and opposite to your example it matters - counter variable is reused to countdown from last allocated object down to 0, when new memory allocation failed. If deallocating other direction you'd need additional variable there:
try
{
array = new double*[size];
// Don't shadow counter here.
for(counter = 0; counter < size; counter++)
{
array[counter] = new double[size];
}
}
catch(std::bad_alloc)
{
// delete in reverse order to mimic other containers.
for(--counter; counter >= 0;--counter)
{
delete[] array[counter];
}
delete[] array;
I had some code thrown at me to 'productionize.' I ran a memory leak checker and it calls out the following line within the 'for' loop below as a memory leak.
someStruct->arrayMap = new std::list<BasisIndex>*[someStruct->mapSizeX];
for(int i=0; i<someStruct->mapSizeX; i++){
someStruct->arrayMap[i] = new std::list<BasisIndex>[someStruct->mapSizeY];
}
Here is how the array map is declared:
struct SomeStruct{
int mapSizeX;
int mapSizeY;
std::list<BasisIndex>** arrayMap;
};
Here are a couple usages of it:
someStruct->arrayMap[xVal][yVal].push_back(tempIndex);
for(it = someStruct->arrayMap[xVal][yVal].begin(); it != someStruct->arrayMap[xVal][yVal].end(); it++){
...
}
The memory leak checker dumped for 5 minutes before I killed it. Then I added the following bit of code in a cleanup routine but it still dumps out 150 warnings all pointing to the line of code within the for loop at the top.
for(int x=0; x<someStruct->mapSizeX; x++){
for(int y=0; y<someStruct->mapSizeY; y++){
someStruct->arrayMap[x][y].clear();
someStruct->arrayMap[x][y].~list();
}
}
std::list<BasisIndex> ** temp = someStruct->arrayMap;
delete temp;
How do I completely delete the memory associated with this array map?
Deallocate the objects in the reverse order that you allocated them.
Allocation:
someStruct->arrayMap = new std::list<BasisIndex>*[someStruct->mapSizeX];
for(int i=0; i<someStruct->mapSizeX; i++){
someStruct->arrayMap[i] = new std::list<BasisIndex>[someStruct->mapSizeY];
}
Deallocation:
for (int i=0; i<someStruct->mapSizeX; i++){
delete[] someStruct->arrayMap[i];
}
delete[] someStruct->arrayMap;
someStruct->arrayMap[x][y].~list(); <-- You should not call the destructor manually. (I didn't even know it was valid to do it that way when placement new wasn't used first...) You need to use delete instead.