Please take a look at this function :
void Remove(char *code){
for (int i = 0; i < _curSize; i++){
if (strcmp(code, products[i]->getCode()) == 0){
delete products[i]; // delete product if found
products[i] = NULL; // reset a pointer
products[i] = new Product(); // create new 'default' product
products[i] = products[_curSize-1]; // copy product at last index at place of deleted product
// delete products[_curSize-1]; // if this command gets exe, program crashes.
products[_curSize-1] = NULL; //
_curSize -= 1;
return;
}
}
So I guess its pretty clear what I try to do. Based on code delete the product from array of product pointers and then place the last product in place of one deleted. I marked where program crashes. If I comment that line it works fine, but isn't that leaked memory? Note that this is for school, so I have to use pointers.
This step seems to have no purpose other than creating a memory leak:
products[i] = new Product(); // create new 'default' product
This step transfers implied ownership of an object:
products[i] = products[_curSize-1]; // copy product at last index at place of deleted product
So this step would not fix a memory leak. It would cause a crash (as you already know it does):
delete products[_curSize-1];
Looking at the whole thing:
void Remove(char *code){
for (int i = 0; i < _curSize; i++){
if (strcmp(code, products[i]->getCode()) == 0){
delete products[i]; // A correct/important step
products[i] = NULL; // Totally useless, but not harmful
// products[i] = new Product(); // Useless and harmful, creates a memory leak
products[i] = products[_curSize-1]; // A correct/important step
// delete products[_curSize-1]; // Very harmful: program crashes.
products[_curSize-1] = NULL; // Maybe useful, anyway not harmful.
_curSize -= 1; // A correct/important step
return;
}
}
Related
I have a pointer to an array of pointers-to-objects, and need to resize the array. I do realize this is a perfect time to use vectors, But I'm not permitted to do so. My code works, but I don't completely follow what I've written, and concerned i may have created memory leaks:
void foo (DataSet &add_data)
{
if (sets == NULL)
{
sets = new DataSet*[1];
sets[0] = &add_data;
}
else
{
DataSet **transfer;
transfer = new DataSet*[num_of_sets];
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
transfer[i] = sets[i];
delete [] sets; // Free the array.
sets = new DataSet*[num_of_sets + 1]; // Create new sets
for (int i = 0; i < num_of_sets; i++) // Copy back
sets[i] = transfer[i];
sets[num_of_sets] = &add_data; // Add the new set
delete [] transfer;
transfer = NULL;
}
num_of_sets++;
}
Why does Visual Studio throw an exception for:
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
*transfer[i] = *sets[i];
but not:
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
transfer[i] = sets[i];
But both code segments compile and run without fault in linux. This code should copy the pointers-to-objects. Is that what is happening with:
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
transfer[i] = sets[i];
And do I need to be concerned if I want to free these objects with say a remove function later?
You do not need to allocate twice, just allocate once the final size:
transfer = new DataSet*[num_of_sets + 1]; // Create new sets - final size
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
transfer[i] = sets[i];
delete [] sets; // Free the array.
sets = transfer;
sets[num_of_sets] = &add_data; // Add the new set
// now no need to delete[] transfer
That way you also get improved exception safety btw. - in your original code, you deleted the sets before allocating the new data to it - if that would throw std::bad_alloc, not only your object will become inconsistent (having a dangling sets ptr because you do not assign null to it after delete) but also the memory allocated to transfer would leak. If you allocate transfer directly to final size before delete[] sets, if that will throw, sets will stay intact and transfer will not leak (because it threw during allocation i.e. did not allocate).
Of course, make sure that you delete[] sets in the destructor (and maybe the pointers as well, in case your set is owning them).
*transfer[i] = *sets[i];
Does not copy addresses, like the other sample (without asterisks) does, it tries to dereference the uninitialized pointer elements of transfer and call operator= on DataSet objects on these addresses.
It's undefined behavior, that's why it appears to work under changed circumstances.
I got following problem.
I want to resize my array of pointers on structure ( car ) . I got following code.
Class Car{
...
char * Owner_Name;
char * carID
};
Class Register {
...
int CarCNT;
int car_num_default;
Car ** dataBase;
Register ()
{ //constructor
car_num_default = 5 ; //for example;
dataBase = new Car * [car_num_default];
}
};
Now when I add 6th. car I need to resize my array of pointer to car. How should I do that without create any memory leak ? Or memory error ? :)
I tried folowing code but it makes some memory leaks..
void Register:: Add ( const char * carID, const char * owner)
{
if (carCNT == car_num_default) // now it's full array need resize
{
car ** tmp = new car * [carCNT]; //create new array ;
for(int i = 0 ; i < carCNT;i++)
tmp[i] = new car(databaze[i]->car_ID,databaze[i]->owner_name);
free(database); //free memory and than alloc new bigger
database = new car * [car_num_default * 5];
for(int i = 0; i < carCNT; i++)
data_by_RZ[i] = tmp [i];
free(tmp);
car_num_def = car_num_def * 5;
}
databaze[carCNT] = new car(....);
carCNT++;
}
Thanks for any help!
Here's a list of obvious bugs in your memory management:
You allocate with new[] but deallocate with free. See Is there any danger in calling free() or delete instead of delete[]?
On reallocation, you create new car instances and copy the data of existing car objects instead of copying the pointers to the existing car obejcts. This causes all the previous cars objects to leak. This bug is only when copying database to the tmp table. The copy from tmp to the new database would be correct if tmp contained the pointers to the old car objects.
You needlessly create a tmp array and copy the database to it. You should simply create the new, bigger array, copy, deallocate the old and then set the database pointer. This bug does not cause a leak, but is entirely pointless and does waste memory bandwidth.*
* Here's the code as requested:
Car** tmp = new Car*[car_num_default * 5];
for(int i = 0; i < CarCNT; i++)
tmp[i] = database[i];
delete[] database;
database = tmp;
Remember that functions destroy their parameters after the function finishes its execution.
Since you are passing carID and owner as pointers and inserting them into the array, the values are destructed after execution and the pointers placed inside the array become invalid causing the leak. Use pointers only when you want to make a change to the pointer itself but never store it as it will soon be destructed.
It seems that you are using pointers in places you shouldnt or where you don't have to. Here is a simpler version of your code that does the same:
Class Car{
...
char Owner_Name;
char carID;
};
Class Register {
...
int CarCNT;
int car_num_default;
Car * dataBase;
Register ()
{ //constructor
car_num_default = 5 ; //for example;
dataBase = new Car [car_num_default];
}
};
void Register:: Add ( const char carID, const char owner)
{
if (CarCNT == car_num_default) // now it's full array need resize
{
car * tmp = new car [carCNT]; //create new array ;
for(int i = 0 ; i < carCNT;i++)
tmp[i] = new car(dataBase[i].car_ID,dataBase[i].owner_name);
free(dataBase); //free memory and than alloc new bigger
dataBase = new car [car_num_default * 5];
for(int i = 0; i < carCNT; i++)
data_by_RZ[i] = tmp [i];
free(tmp);
car_num_def = car_num_def * 5;
}
Car x(...);
dataBase[CarCNT] = x;
carCNT++;
}
Finally, I have four points to make:
1) This doesnt seem like C++ or you are not using proper naming
2) I am not sure how this code complied since most variable names are incorrect (i tried to fix what i came across).
3) Excessive use of pointers (memory locations in other words) is the main cause of memory leaks. Handle them with care and only use them when you have to.
4) IFFF you have to use pointers that much then add destructors (Anti-constructor) like this ~Car or ~Register on any class that is used as a pointer to signal when the element is destroyed. That way you know where the leak is taking place by writing to the console or handle the destruction gracefully.
Hope that helped
I was working with dynamic memory from a book that I got. As far as I understand every time that we create a new variable we need to delete it, and set the pointer to null, so we don't have dangling pointers .
I created a program that stores values from users in a dynamic Array of [5], and whenever the user adds more I "expand" the array. When expanding, I use a temporary new array that gives me a tough time when I try to delete it. Why does this happen?
size_t arraySize(5), index(0);
int inputvalue(0);
int *ptemporal(nullptr);
int *pvalues = new int[arraySize];
for (;;){
cout << "Enter value or 0 to end: ";
cin >> inputvalue; //enter value
// exit loop if 0
if (!inputvalue) //if 0 break
break;
pvalues[index++] = inputvalue; //store values on pivalores
if (index == arraySize){ //if limit reached create space
cout << "Limit reached. Creating space...";
arraySize += 5; //5 new memory blocks
ptemporal = new int[arraySize]; //temporal value holder.
for (size_t i = 0; i < arraySize - 5; i++) //xfer values to temporal
ptemporal[i] = pvalues[i];
delete[] pvalues; // delete values to
pvalues = ptemporal; // assigning the same addres to pvalues.
**delete[] ptemporal; //causes a problem if I use the delete. if i comment the program works just fine.**
ptemporal = nullptr;
}
}
return 0;
}
**The two asterics are just to show were the problem occurs.
Your issue is that you are deleting ptemporal right after you copy the pointer to pvalues:
pvalues = ptemporal; // assigning the same addres to pvalues.
delete[] ptemporal; //causes a problem if I use the delete. if i commentt the program works just fine.**
In other words, you delete the memory you just created! So the next time you expand the vector, you try to delete it again, resulting in a double free error. This sort of error is where a debugger helps, so you can watch the variable values as your program executes.
// start
ptemporal = nullptr;
pvalues = /* location A */;
// first expansion
ptemporal = /* location B */;
// copy values from location A to B
delete[] pvales; /* location A */
pvalues = ptemporal; /* location B! */
delete[] ptemporal; /* location B */
ptemporal = nullptr;
// second expansion
ptemporal = /* location C */;
// copy values from location B to C, should segfault
// then you delete pvalues (aka location B) again!
// this results in a double free error
delete[] pvales; /* location B */
To fix this, simply remove the line delete[] ptemporal;
You dont need to delete pTemporal. You've deleted pValues and wish to hand over pTemporal into it.
delete [] pValues;
pValues = pTemporal;
pTemporal = NULL;
So, I'm getting a heap corruption error in the Expand method for an Ordered List Class I'm working on. The expand method is called when the client tries to Insert() a new item into the list, and there isn't currently room left in the array. When I take the delete line out, the program runs fine, but I know I have an inaccessible object each time it expands. However, when I put the delete line in, the program explodes at run-time.
Additionally, this only happens in my Expand() method. It doesn't do this in my Contract() method, which is called each time there is a deletion from the list that brings the number of list elements down below 1/4 the total space currently available, it cuts the size in half. I can delete the old list in this method without any problems.
GetListPtr(), SetListPtr(), and GetLength() are all inherited from a ListClass object, which I received in the form of a header file and object code, so I'm not sure exactly how they work. ItemType is a struct, only containing an integer field, key.
I've read a number of questions on here already and didn't find any that seemed to provide any help in regards to my situation.
void OrdListClass::Expand()
{
ItemType* newList = new ItemType[size * 2];
ItemType* temp = GetListPtr();
size = size * 2;
// Copy the current list to the new list.
for(int i = 0; i < GetLength(); i++)
newList[i] = temp[i];
// Point to the new list.
SetListPtr(newList);
// Delete the old list
delete temp; <-- This line
// Reset the pointers
temp = nullptr;
newList = nullptr;
}
void OrdListClass::Contract()
{
ItemType* newList = new ItemType[size / 2];
ItemType* temp = GetListPtr();
size = size / 2;
// Copy the old list into the new one
for(int i = 0; i < GetLength(); i++)
newList[i] = temp[i];
// Set the list pointer to point to the new list
SetListPtr(newList);
// Delete the old list
delete temp;
temp = nullptr;
newList = nullptr;
}
Thanks again for reading this, any and all help is appreciated.
I assume that your list was allocated with:
ItemType* newList = new ItemType[size * 2];
If that's the case, you need to do:
delete[] temp;
Elements allocated with new[], need to be deleted with delete[].
http://www.cplusplus.com/reference/new/operator%20delete[]/
I am working on a lab dealing with queues, which I don't think is entirely relevant. My task is to create a "priority queue" and the best way I could think of to do it is as follows
void IntQueue::enqueue(int num,int priorityOfEntry)
{
if (isFull())
cout << "The queue is full.\n";
else
{
// Calculate the new rear position
//insert correct lab code here haha
if (priorityOfEntry == 1)
{
rear = (rear + 1) % queueSize;
queueArray[rear] = num;
queueSize++;
}
else if (priorityOfEntry == 2)
{
queueSize++;
int* newArray = new int[queueSize];
newArray[0] = num;
for(int counter = 0;counter< queueSize; counter++)
{
newArray[counter+1] = queueArray[counter];
}
queueArray = newArray;
delete [] newArray;
}
else cout << "invalid priority" << endl;
// Insert new item
// Update item count
numItems++;
}
}
I only have 2 priority levels, 1 and 2, that I explain in the main program. when they all have equal priority it of course works fine, but when I bump on up in priority it throws an error at my destructor.
I really don't think this is the right way to approach this lab, but It seems to work.. at least if I can actually get this memory error fixed.
I figure the only problem could be in that I change the address of what the destructor thinks it will delete.. but I thought pointers would already kind of account for that.
I understand I need to learn to debug my own programs. I really do. but sometimes I just stare at code and there is nothing but a brick wall there. Guess that's what a nudge in the right direction is for.
queueArray is a dangling pointer after this:
queueArray = newArray; // Both 'queueArray' and 'newArray' point to
// the same memory after this assignment.
delete [] newArray;
as the memory that queueArray is pointing to has been deleted. Any attempt to access or destroy queueArray is accessing memory that has already been destroyed. The correct order is:
delete[] queueArray;
queueArray = newArray;
Additionally, there is a potential out-of-bounds access in the for loop that performs the copying:
for(int counter = 0;counter< queueSize; counter++)
{
// When 'counter == queueSize - 1'
// 'newArray[counter + 1]' is one past the end.
newArray[counter+1] = queueArray[counter];
}
Here:
queueArray = newArray; // queueArray and newArray point to the same place
delete [] newArray; // that place gets delete[]ed
you are making queueArray point to the same place as newArray, but then you are deleting the array that lies in that location. So queueArray is left pointing to memory you have given back to the OS, i.e it is now a dangling pointer.
You need to delete queueArray[] first, then assign newArray to it.
Okay, I got it, I don't know why I thought I needed to add another member of the array when the priority switched, I think i'm just tired.
So that was the extra array member
and i think that was the only other problem