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.
Related
I know that if I use new[] I have to delete[], but this is my doubt:
Declaration:
char **data; // This will be a bi-dimensional array
Construct:
data = new char*[10];
for (int i=0; i<10; ++i)
{
data[i] = new char[128];
}
Destroy:
for (int i=0; i<10; ++i)
{
delete data[i]; // <--- delete or delete[] ???
}
delete[] data;
Another case where I have an array of objects:
Declaration:
myClass **object;
Construct:
object = new myClass*[10];
for (int i=0; i<10; ++i)
{
object[i] = new myClass();
}
Destroy:
for (int i=0; i<10; ++i)
{
delete object[i]; // <--- this object[] is not an array, right?
}
delete[] object; // <--- Is this correct?
You basically answered your own question. Since data[i] is an array, you need to delete[]. object[i] was allocated with new so you would delete it. Since both object and data are arrays, you would need to delete[] them.
The first dimension of your pointer data is an array. The second dimension is an array as well. Therefore you must use delete[] to properly deallocate memory reserved from your new[].
For your object, the first dimension was allocated using new. So you must use delete. Then use delete[] on object because it's an array.
The mnemonic that you mentioned (delete [] for new [] and delete for new) is a a good practice, and should be enforced as mandatory.
However, there is a huge difference between delete and delete[] when it comes to base types (int, char, void*,etc) and classes.
The difference between new and malloc is that one calls the constructor while the other doesn't. Same relation happens with delete and free when it comes to destructor.
In your example you gave two situations : one when an array of simple type is allocated and one with an array of objects allocated.
The behavior is different.
For the simple type, delete and delete[] will produce the same result .
Reason ? well, you basically allocated a block of 10 pointers of char* , so deleting it is no problem (the allocated memory paged will be freed).
In other words, if you have
char* a = new char[100];
then
delete a;
and
delete[] a;
will produce the same results (note that you used a new []);
This behavior is different when it comes to objects that have constructors and destructors.
Let's take the following class :
class SimpleClass
{
public:
SimpleClass(){printf("constructed");
~SimpleClass()(printf("destructed");
}
and the following code :
SimpleClass* arr1 = new SimpleClass[5];
SimpleClass* arr2 = new SimpleClass[5];
char* arr3 = new char[5];
char* arr4 = new char[5];
delete[] arr4;
delete arr3;
delete[] arr2;
delete arr1; //notice the surprise ?
Run the above code (if you can) in Visual Studio and open up a memory viewer. You will see that the memory allocated at ptrs arr4 and arr3 is correctly invalidated, same for arr2.
However when attempting to delete arr1 without the [] call you will get a SigSev error .
Why ?
Because in case of arr2 you have an array of allocated objects, and the delete[] statement means "pass through each destructor from the array"".
In case of arr1 it means : call the destructor of the object allocated at pointer arr1... a bit unfortunate if you take into account that there is more then 1 object allocated at that address, and you end up attempting to release a page which is lesser then the initial allocated size.
Bottom line :
delete[] for new[] and delete for new !
Works every time !
I have an array of pointers (that I created by calling new ptr*[size]). All of these pointers point to an object that was also put on the heap.
What is the proper way to delete the array and all new'd ptr's?
This is what I do now:
for (int i = 0; i < size; i++) delete array[i];
delete[] array; // Not sure since this double deletes array[0]
Does this do what I think it should?
Thanks
Every pointer allocated with new gets a corresponding delete. Every pointer allocated with new [] gets a corresponding delete []. That's really all you need to know. Of course, when you have a dynamically allocated array which contains dynamically allocated pointers the deallocation must occur in reverse order.
So it follows that the correct idiom would be...
int main()
{
int **container = new int*[n];
for(int i = 0; i < n; ++i)
container[i] = new int[size];
// ... and to deallocate...
for(int i = 0; i < n; ++i)
delete [] container[i];
delete [] container;
}
And then of course I say "stop doing that" and recommend you use a std::array or std::vector (and the template type would be unique_ptr<int>).
Yes, that does what you think it should. Since you did new for each element, you have to delete each element. And since you did new[] for the entire array, you need to delete[] the entire array.
As #djechlin rightly says in the comments, there's not really enough information to go on, but I'm presuming your prior code is something like this:
int** array = new int*[5];
for (int i = 0; i < 5; i++) {
array[i] = new int;
}
Note that array is not actually an array type. It is a "pointer to pointer to int" and the array of pointers it points to was allocated with new[]. That's why you need to delete[] it.
Yes. First you have to free the object each pointer in the array points to, then you have to free the array itself. In that order. If you reverse the order you'll have no reference to the objects and will leak a lot of memory.
Yes, first you delete each object to which elements of array point, and then you delete array of pointers itself. If you want to check your memory management, you can use tools like valgrind, they will be able to spot most errors.
I would like to know if there is a way to delete a pointer array without touching the pointed objects in memory.
I'm writing a restriction routine for a HashSet I implemented a couple of days ago, so when the hash table is full it gets replaced by another double sized table. I'm representing the hash table using an array of pointers to an object (User), and the array itself is declared dynamically in my HashSet class, so it can be deleted after copying all its content to the new table using a hash function.
So basically I need to:
Declare another table with a size that equals the double of the original array size.
Copy every pointer to User objects from my original array to the new one applying my hash function (it gets the User object from memory and it calculates the index using a string that represents the user's name).
After inserting all the pointers from the original array to the new one, I will have to free the allocated memory for the original array and replace the pointer in my HashSet class (member private userContainer) with the location of the new one (array).
The problem is that if I use delete[] userContainer to free the allocated memory for it, it will also delete every object in memory so the newly created replacement array will point to freed positions in memory!
What you describe does not sound right.
Let's say you have a class A and you create an array of As with:
A** array1 = new A*[32];
Then fill it:
for(int i = 0; i < 32; ++i)
array1[i] = new A();
Doing a delete[] array1 does not free the elements of array1.
So this is safe:
A** array1 = new A*[32];
for(int i = 0; i < 32; ++i)
array1[i] = new A();
A** arary2 = new A*[64];
for(i = 0; i < 32; ++i)
array2[i] = array1[i];
delete [] array1;
for(i = 0; i < 32; ++i)
// do something with array2[i]
In general, when you delete an array of pointers, whatever objects the pointers pointed to remain in existence. In fact, this is a potential source of large memory leaks.
But in some sort of reference-counted environment (eg, Objective-C or Qt), when you delete an array OBJECT (vs a simple [] array) then the reference counts are decremented and the objects will be deleted if the count goes to zero.
But if you're restructuring a hash table you'd better have somehow saved the pointer values before you delete the array, or else all the addressed objects will be lost. As you save them you can increment their reference counts (if you do it right).
(It would help to know what language you're dealing with, and what you mean by "array".)
I don't think your problem exists. Here's a baby example to show that there's nothing to worry about:
Foo * brr[10];
{
Foo * arr[10];
// This is not touching the objects!
for (Foo * it = arr; it != arr + 10; ++it) *it = new Foo;
std::copy(arr, arr + 10, brr);
} // no more arr
for (Foo * it = brr; it != brr + 10; ++it) delete *it; // fine
You can copy the pointers around freely as much as you like. Just remember to delete the object to which the pointers point when they're no longer needed.
A perhaps trivial reminder: Pointers don't have destructors; in particular, when a pointer goes out of scope, nothing happens.
Do you know the difference between malloc/free, new/delete and new[]/delete[]?
I figure that you might want to not use new[]/delete[] in your situation, as you don't want destructors to be called I guess?
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.
Looking for some help with arrays and pointers and explanation of what I am trying to do.
I want to create a new array on the heap of type Foo* so that I may later assign objects that have been created else where to this array. I am having troubles understanding what I am creating exactly when I do something like the following.
Foo *(*f) = new Foo*[10];
Also once I have created my array how do I access each element for example.
(f + 9)->fooMember(); ??????
Thanks in advance.
Foo *(*f) = new Foo*[10];
The parentheses in the declaration are unnecessary, so this is the same as:
Foo **f = new Foo*[10];
In any case, the new Foo*[10] allocates space for ten Foo*s and leaves them uninitialized. It returns a pointer to the initial Foo* in the array (the zeroth element), which you assign to f.
To access elements of the array, you simply use subscripting:
f[0] = new Foo;
f[0]->fooMember();
Remember that anything you create using new[] must be freed once when you are done with it by calling delete[] on the pointer. For example:
delete[] f;
This does not delete the elements pointed to by the Foo*s in the array. If you create Foo objects using new, you must delete them before you delete the array. For example, to free the element we created above:
delete f[0];
You can create an array of pointers using the following code:
Foo** f = new Foo*[10];
Then access the elements with:
f[9]->fooMember();
Be sure to clean up afterwards:
delete[] f;
Thanks.
When you have this situation, you might find the following code snippet useful:
First the initialization:
Foo** f = new Foo*[10];
for (int i = 0; i < 10; i++) {
f[i] = new Foo;
}
Then to access each element in the f array which is what you asked, but you won't be able to do so unless you allocate memory properly for each member by calling the constructor as done above:
f[9]->fooMember();
Finally, to keep things tidy and to prevent memory leaks:
for (int i = 0; i < 10; i++) {
delete f[i];
}
delete[] f;
Arrays and pointers aren't very C++ish. How about
std::vector<std::shared_ptr<Foo> > f;
f.push_back(std::make_shared<Foo>(whatever, arguments, you, need));
// ...
f[9]->fooMember();
// ...
No manual cleanup needed :-)