Leaking memory when not freeing internal cells? - c++

My professor wrote the following code:
template <class T>
Set<T>& Set<T>::operator=(const Set<T>& set) {
if (this == &set) return *this;
T* data_temp = new T[set.size];
try {
for (int i = 0; i < size; ++i) {
temp_data[i] = set.data[i];
}
} catch (...) {
delete[] temp_data;
throw;
}
delete[] data;
data = temp_data;
size = maxSize = set.size;
return *this;
}
And he pointed that temp_data[i] = set.data[I]; calls operator=, and I am wondering why this doesn't leak memory?
For example if operator= failed in the 4th loop then we are deleting temp_data, but what about the values of the first 3 cells in temp_data which were allocated inside operator= code? we aren't freeing them.

For example if operator= failed in the 4th loop then we are deleting temp_data, but what about the values of the first 3 cells in temp_data which were allocated inside operator= code? we aren't freeing them.
new[] allocates the entire array and constructs all of the T objects in it, before the loop is reached. delete[] destructs all of the objects in the array, and deallocates the entire array. So, it is the responsibility of T's constructor and destructor to initialize and finalize T's data members properly.
The loop merely updates the content of the data members of the objects in the array. It is the responsibility of T::operator= to copy and free T's data members properly as needed.
There is no leak in this Set::operator= code. However there is a minor mistake - the loop needs to use set.size instead of size.
for (int i = 0; i < set.size; ++i)
The new array is allocated to set.size number of elements, so that is how many elements the loop needs to copy.
Using size for the loop, if the Set being assigned to is smaller than the Set being copied, the new array won't copy all of the elements. And if assigning to a Set that is larger, the loop will go out of bounds of both arrays.
If you are experiencing a leak, it would have to be in either T::operator= or in T::~T(), neither of which you have shown. Assuming Set::Set() and Set::~Set() are initializing and freeing data properly, this is.

Lets remove some complications from this code. Lets assume T == int and instead of storing many ints we only store one:
int_store& int_store::operator=(const int_store& set)
{
int* temp_data = new int; (1) allocate
try
{
*temp_data = *set.data; (2) assign
}
catch (...)
{
delete temp_data; (3) free temp
throw;
}
delete data; (4) free old
data = temp_data;
}
The method has one allocation int* temp_data = new int (1). It the tries to assign the other sets data to that temp value (2). When this fails the temp has to be deleted (3) otherwise we can replace the old data with the new data stored in temp_data and before doing that we have to delete the old data (4).
There is no allocation in the try block. All memory allocated in the function is either deleted (when assignment fails) or it is used to replace the old data, in which case the old data is deleted before.
If data is an array instead of a single int (almost) nothing changes and there is no leak. The elements you worry about are already allocated in the line T* data_temp = new T[set.size]; and then delete[] temp_data; will delete all of them.

Related

How do I manage to create a vector class in c++?

I was introduced to pointers, I quite get it. but I don't know how to store variables in the vector class using pointers.
Here is what I got from my understanding but how should I complete it?
class Vector{
int size;
int* element;
public:
vector(int x);
int size() const { return size }
};
first, you need to define a value that stores the current size - (number of elements inside the vector) - to be able to add values at the end of the vector.
int curr_vec_size;
also, the actual size of the vector should be saved in a variable to check every time you add a value that allocated memory is not full
int memory_size;
second, you need to allocate memory dynamically by using "new" in the constructor
vector(int size)
{
element = new int[size]; //allocating memory (array of integers)
memory_size= size; //size of allocated memory
curr_vec_size= 0; //no values in the vector
}
then you can make a method that takes an int value and adds it to the dynamic array.
void add_value(int passed_val)
{
if(curr_vec_size < memory_size)
{
element[curr_vec_size]=passed_val; //adding the value in the vector
curr_vec_size ++; //because you have added a new value
}
else
cout<<"vector is full \n";
}
Finally, don't forget to delete the memory you've allocated by using destructors that deletes the pointer to this allocated memory.
vector()
{
delete[] element;
}
To complete what you started, you simply need to use new[] operator to allocate memory to store your int values:
vector(int x)
{
size = x;
element = new int[size]; // this allocates an array of int with a size of "size"
}
Then, you can use element[i] to access i's element of your array.
You'll later need (it's a must) to release allocatd memory to prevent memory leak by implementing a destructor:
~vector()
{
delete [] element;
}
Note that you should (must) also also follow at least the rule of 3 to have you vector be copiable.

Unreadable memory when I create pointer array in c++

I'm new to pointers and dynamic memory. The program is supposed to be an array-based stack.
I need help with an error that occurs when I try to allocate memory to the pointer variable _pArr in the .h-file. When I try to create a new array with new double[] I get an 'unreadable memory' error message when I debug the code.
In the code down below I have created a new array in the .cpp-file and then copy it to the _pArr pointer, but I still get the same error.
class CStack{
public:
Stack(void);
~Stack(void);
.
.
.
private:
int _capacity=NULL;
int _size=0;
double* _pArr;
}
CStack::CStack(void)
{
if (_capacity == 0){
_capacity = 10;
}
else{
_capacity = _capacity * 2;
}
double* arr;
arr = new double [_capacity]
_pArr=arr;
delete[] arr;
}
Why does this error occur and how can I fix it?
Here's what your code is doing in the constructor:
// Allocate memory for an array and set arr to point to that array.
double* arr;
arr = new double [_capacity]
// Set _pArr to point to the same array.
_pArr=arr;
// Delete the array that arr and _pArr point to. If you
// deference _pArr after this, bad things will happen.
delete[] arr;
So you shouldn't be deleting the array immediately after you allocated it. (There's also a missing semicolon there.) Getting rid of that will likely fix your problem, but then you then need to delete the array in the class's destructor. And if you must use new[]/delete[], it would be far easier to do it in a single step, rather than creating a useless temporary variable:
CStack::CStack(void)
{
if (_capacity == 0){
_capacity = 10;
}
else{
_capacity = _capacity * 2;
}
_pArr = new double [_capacity];
}
CStack::~CStack(void)
{
delete[] _pArr;
}
Unrelated to your question, but that code that doubles _capacity doesn't do anything useful, as capacity will always be zero when the constructor is called. If you intended for this to expand an existing CStack, then you will need to put it in a method, and will need to worry about creating a new array for the stack, copying the contents of the old one into the new, and then deleting the old one.

How memory will be deleted?

Let's say I have structure
struct Foo {
int whatever;
int whatever2;
...
};
And I have this type of array
Foo **array = new Foo*[128];
Then, to every pointer I assign new structure
for (int i = 0; i < 128; i++)
array[i] = new Foo;
Then, after a while I deallocate:
delete[] array;
How memory will be deallocated?
Only the space for pointers will be freed
Space for pointer + the objects pointed by those pointers themselves?
Your code leaks memory. You need to call delete once for every new call (assuming the new doesn't fail and either return NULL or throw bad_alloc). So, in this case, you'll need to have a similar loop to the one that calls array[i] = new Foo; that does delete array[i];
I think this is one of points in Scott Meyers book, Effective C++ have read long back. But basic idea is, to avoid memory leak when you use new. make sure to call delete as many times as new is called and map new with delete and new[] with delete[] accordingly. so in your case new is called 128 times in for loop and new[] is called once, so similarly delete should be called same way to array[i] 128 times and delete[] should be called once for array. Hope this helps.

How does dynamic space allocation actually work in this algorithm?

I have made for school purposes my own take on a dynamically allocated array using templates.
While what I'm about to ask works, I don't know how and why and I've reached the point where I need to know.
template <typename TElement>
DynamicArray<TElement>::ensureCapacity () {
if (capacity >= elemNumb) {
return; //we have space to store the values
}
//we need to allocate more space for the values
TElement *auxArray = myArray;
//create space to hold more numbers
capacity = capacity * 2;
myArray = new TElement[capacity];
//copy the values
for (int i = 0; i < size; i++) {
myArray[i] = auxArray[i];
}
//release the memory
delete[] auxArray;
}
I need to know: TElement *auxArray = myArray; How does this work ? is it using pointers, are elements copied one by one ? I need to understand how it works so that I can figure out the complexity of my algorithm. I don't mind if some one tells me the complexity but the real answer I'm looking for is how does that work ?
Also myArray = new TElement[capacity]; I do this before deleting the old myArray does this delete the old one ? or is it still floating somewhere in memory in one form or another ?
This
TElement *auxArray = myArray;
just means that auxArray points to whatever myArray is pointing to. There is no copying of anything else, it is just a pointer copy.
This
myArray = new TElement[capacity];
means that myArray now points to a new, dynamically allocated TElement array. The expression doesn't delete anything. But auxArray is pointing to what myArray was pointing before this assignment, so when you delete auxArray, you release the resources originally pointed to by myArray.

C++ array of pointer memory leaks

In my class I have a dynamically allocated array of pointers. My declaration:
array = new Elem* [size];
for (int i = 0; i < size; i++) {
array[i] = NULL;
}
So there is an array of pointers, where each pointer points to a simple Elem struct.
The main question is, how should I properly deallocate the array. If I use only:
for (int i = 0; i < size; i++) {
delete array[i];
}
Valgrind reports 1 not-freed block, which is traced to the line where 'array = new Elem* [size];' states.
On the other hand if I add to the previous code:
delete array;
Which I thought is correct, valgrind reports 0 not-freed blocks, which is perfect, BUT it reports
Mismatched free() / delete / delete []
exactly on the line where 'delete array;' is. I tried 'delete []array' too, but that's just "1 not-freed blocks" too then! If somebody could explain me the proper way it would be much appreciated.
EDIT:
So using:
for (int i = 0; i < size; i++) {
delete array[i];
}
delete[] array;
is working probably fine. It is working in one of my classes (I have two similar) the other still reports some small leak. I would think it's just a minor bug somewhere, but valgrind still points to the line where
array = new Elem* [size];
stands.
EDIT2:
I solved this as well, thank you for your exhausting contribution!!
You need:
delete [] array;
Because it's an array.
I just noticed your note that you tried this too - it's the proper thing to do so I don't know why you'd still be getting an error.
Edit: This deserves a more thorough explanation.
When you create a pointer using new, the pointer may be to a single element or an array of elements depending on the syntax you use. But the pointer type is the same in both cases! The compiler relies on you to know what the pointer points to and treat it accordingly.
Elem ** single = new Elem*; // pointer to one pointer
single[0] = new Elem; // OK
single[1] = new Elem; // runtime error, but not compile time
Elem ** array = new Elem* [2]; // pointer to array of pointers
array[0] = new Elem; // OK
array[1] = new Elem; // OK
When you delete a pointer, the destructor is called for the object it points to or for each element of the array. But since the pointer type is the same in each case, the compiler relies on you to give it the proper syntax so it knows what to do.
delete single;
delete [] array;
In your case the elements of the array are pointers also, and pointers don't have destructors. That means those pointers won't be deleted and will become memory leaks if you don't delete them first. You were correct to have a loop to delete them individually before the final delete.
You should free everything in the array (if dynamically allocated) and then free the array itself.
for (int i = 0; i < size; i++) { // only free inside if dynamically allocated - not if just storing pointers
delete array[i];
}
delete[] array; // necesarry
The syntax for deleting an array is like this:
delete[] array;
Your for loop to delete the objects pointed to by the elements of the array is fine. The deletion of the array itself is the only problem. You need both the for loop and then the delete[] to dispose of the array itself.
for (int i = 0; i < size; i++) {
delete array[i];
}
delete[] array;
I suspect that you have tried using the for loop, or the delete[], but not both together. And if when you do that you still have leaks or errors, then you would need to show us the code that allocates the pointers that are elements of the array.
Using std::vector<> instead of an array would mean that you could stop worrying about these nitty gritty details and move to higher level of abstraction.
In this case, you need both.
for (int i = 0; i < size; i++) {
delete array[i];
}
delete[] array;
You call delete exactly once for each time you called new.
Note that although you need to call delete[] array here (because you allocated it with new[]), the delete[] operator does not call the destructors on the objects pointed to by elements of the array. This is because the delete[] operator calls destructors on objects in the array, and your array contains pointers but not objects. Pointers do not themselves have destructors.