I am creating a program that uses an array of objects declared with
Element * elements = new Element[number];
where an element is a class that has/needs a its own destructor.
when I go to delete this would I use just use array delete, and have the program worry about calling the destructor:
delete [] elements;
or do I call the destructor for each item explicitly with keyword delete:
for(int ii = 0; ii< ArraySize; ii++)
delete elements[ii];
delete [] elements;
Note: I understand that I could probably use something like boost::ptr_vector, but I wanted similar to hashTable functionality (so the for loop would need additional information, but that is outside of the direct scope of this question) which is why I am using a traditional array. I would still like to know which behavior is needed to avoid memory leaks.
The first one. You should
delete [] elements;
The second one is incorrect and should give you errors if you try to compile it.
Yes, delete [] elements; should be sufficient.
You'd use your second piece of code with something like:
Element **elements;
elements = new Element *[rows];
for (int i=0; i<rows; i++)
elements[i] = new Element;
This combination rarely makes much sense though. To make at least some sense, each row would itself be a dynamically allocated array as well:
elements = new Element *[rows];
for (int i=0; i<rows; i++)
elements[i] = new Element[row_len];
In this case, your deletion would look something like:
for (int i=0; i<rows; i++)
delete [] elements[i];
delete [] elements;
As you're doing it right now, however, none of what you've said really justifies home-rolled dynamic allocation at all. std::vector<Element> elements(number); would work perfectly well.
Related
I think it may probably an assignment error of shared_ptr. I wrote some code regarding my error about shared_ptr of vector containing int pointer. The error occurs the 2-th loop of j-loop. Please let me know what's the mistake in the code. And I wonder whether 'delete vec.get()' is correct for free the memory of the vector.
int i,j;
shared_ptr<vector<int*>> vec = NULL;
for (j = 0; j < 2; j++)
{
vec = shared_ptr<vector<int*>>(new vector<int*>());
for (i = 0; i < 5; i++)
{
int* ia = new int[10];
vec->push_back(ia);
}
delete vec.get();
}
From what you are showing, there is no need for the smart pointer or the raw pointers. The following code has the same effect as what you seem to intend, except that it also properly initializes all the int elements to zero, which your current code does not do:
vector<vector<int>> vec;
for (int j = 0; j < 2; j++)
{
vec = {5, vector<int>(10)};
// Do something with vec
}
The concrete problem with your current code is that you are trying to delete the raw pointer owned by the shared_ptr. The shared_ptr will delete the owned pointer when its own lifetime ends and no other shared_ptr instance referring to the raw pointer exists anymore. That is its purpose.
If you want to delete the int array you allocated for the int* pointers in the vector, then you need to decide which of the pointers at which index you want to delete:
delete[] (*vec)[index];
vec is the shared_ptr, *vec is a reference to the owned vector<int*>, (*vec)[index] is a reference to the int* stored in the vector<int*> at index index. You need to use delete[] instead of delete, because you allocated with the array form of new.
Given the way your code is structured, you would need to call delete[] for each index of the vector once to avoid any memory leak. Since doing that manually before the vector is destroyed violates the RAII principle, one would use std::unique_ptr for the inner int* instead of raw new. That being said, I already mentioned above that I don't see any reason for pointers of any kind at all.
Below code should work for you:
for (int j = 0; j < 2; j++)
{
auto vec = std::make_shared<vector<int*>>();
for (int i = 0; i < 5; i++)
{
int* ia = new int[10];
vec->push_back(ia);
}
for (int i = 0; i < 5; i++)
{
delete[] vec.get()->at(i);
}
}
I do not understand requirement of this type of strange code. If you are using smart pointer, Why Share_ptr instead unique_ptr? why to call delete? Why you allocate the memory to int* when can be handled by vector of integer. Think on it.
No need to declare and then allocate the memory.
Hope this will help you.
I am writing a program which needs to have an array of pointers to a struct SMesh, specifically
SMesh **mesh_arr;
When I work with an instance that has only one pointer in the array, everything is OK. But when I try to work with instance that has got two (or more) of them, Valgrind goes crazy with "Invalid write of size...".
I initialize it like this (with counter being the number of SMeshes that I need pointers to) :
SMesh **mesh_arr = new SMesh*;
for (int i = 0; i < counter; i++) mesh_arr[i] = new SMesh;
And delete it like this :
delete mesh_arr;
Do I delete it the wrong way or have I missed something?
You have to allocate enough elements to have the entire array, not only 1 element.
SMesh **mesh_arr = new SMesh*[counter];
for (int i = 0; i < counter; i++) mesh_arr[i] = new SMesh;
Using new[], you have to use delete[] to delete it.
delete[] mesh_arr;
Also don't forget to delete the individual SMeshs allocated.
You can avoid pointer trouble with a vector. No need to explicitly delete either.
#include <vector>
auto mesharr{std::vector<std::vector<SMesh>>(rows, std::vector<SMesh>(cols))};
You have only allocated one pointer to your structure in your new statement. Try
SMesh ** mesh_arr = new (SMesh*)[counter];
Say I want to declare an array of pointers to a specific object like
Object *objects = new Object[size];
and then add some new objects to my dynamically allocated array
for (int i = 0; i < size; i++){
Object* obj = new obj;
objects[i] = *obj;
}
is it enough to deallocate all memory by just calling delete[] on the array, or do I have to loop through the array first and call delete on each object? Or is this stupid to do in practice?
You always have to delete everything you new in some way. That means, you would need to delete obj in every iteration to avoid leaks. Note that you never really store the Object obj points to, but a copy of it.
The way you do it right know is quite unusual and not very handy anyway: The loop you showed does nothing useful since the new Objects[size] already default constructed your Objects. In particular, it does not add any elements, they are already there. You could just leave that out. If you want to change the content of your array, e.g. do more initialization, your loop would usually look more like this
for (int i = 0; i < size; i++){
objects[i] = newValue;
}
Remember, the Objects are already there after new Objects[size]!
In practice, you would be much better of with a
std::vector<Object> objects(size);
(or maybe, if the above does not fit your usecase, a
std::vector<std::unique_ptr<Object>> objects(size);
, but I feel like that is unlikely to be the case). For a good overview of what a std::vector can do and how to use it, read the documentation. Probably most importantly for you: You can index it just like an array.
First, you have to follow the deallocation is reverse order of allocation.
So number of times new that many times delete , similarly number of times new [] that many times delete []
// Assuming objects as array of pointers [ Object **objects ]
for (int i = 0; i < size; i++)
{
delete objects[i] ;
}
delete [] objects;
And your correct allocation should go as:
Object **objects= new Object*[size];
for (int i = 0; i < size; i++) {
objects[i] = new Object;
}
Also , you should use smart pointers std::unique_ptr for hassle free memory management
std::vector< std::unique_ptr<Object> > objects ;
You are storing an array of Objects and not pointers to Object. This means that they won't be deleted when you delete the array and the memory will leak.
If you want to store pointers to Objects in your array then you need to declare it as Object **objects = new Object *[size]; and then you will have to delete all the pointers in the array.
So the better code will look like:
//Allocation:
Object **objects = new Object *[size];
for (int i = 0; i < size; i++){
objects[i] = new Object;
}
//Deletion
for (int i = 0; i < size; i++){
delete objects[i];
}
delete [] objects;
An even better solution would be to use vectors and smart pointers and then you don't need the deletion code at all.
//Allocation:
vector<unique_ptr<Object>> objects;
for (int i = 0; i < size; i++){
objects.push_back(make_unique(new Object));
}
//Deletion
//Hey where did all the code go.
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.
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.