I have a question concerning deleting a dynamic array of pointers in C++. Let's imagine that we have a following situation:
int n;
scanf("%d", &n);
Node **array1 = new Node*[n];
/* ... */
where Node is a certain structure defined beforehand. Suppose that after allocation with the new operator, we change the content of the array1 (but we do not delete anything!). What is the proper way to delete the array1 and all its content if there is a possibility of repeated pointers in the array (without sorting them or inserting into the set, in linear time)?
Using this allocation:
Node **array1 = new Node*[n];
The contents of array1 are undefined. Each element is a Node*, and because the memory is uninitialized, the value could be anything.
Allocating an array of pointers does not construct objects of the pointed-to class.
So whatever pointers you put into the array, the objects they point to need to be constructed and destructed elsewhere.
So to answer your question, the proper way to delete array1 is
delete[] array1;
However, note that this will not result in destructors being called for each Node* - you should deal with whatever you put into the array before you delete the array.
EDIT:
I was confused by the original question, which mentioned "change the value" in the array, as if there was a valid value in the array as allocated in your example.
BUT... now that I understand you want to keep track of the pointers for deletion later, perhaps you can just create another array for that purpose where each pointer exists only once. So you have the array you currently have above, which contains pointers to nodes that might be repeated, for whatever purpose you're using it. Then you have another array for the express purpose of managing the deletion, where each pointer occurs only once. It should be easy enough to set something like nodeCleanupArray[i] = pNewNode right after pNewNode = new Node(), then you can blast through that array in linear time and delete each element. (Which means you wouldn't bother inspecting the elements in array1, you'd rely on nodeCleanupArray for the cleanup)
There are MANY solutions to this sort of problem, but the most obvious choice would be to change it to use
std::vector< std::shared_ptr<Node> >
Now you will have a reference counted pointer without writing any code, and an "array" that doesn't need to know it's predefined size.
You can of course implement a reference counted object within Node, or your own container object to do the same thing, but that seems like extra hassle for little or no benefit.
Try mark and sweep :) You are trying to implement a managed environment.
Here is an example:
struct Node
{
...
bool marked;
Node() : marked(false)
{}
};
Now delete:
void do_delete(Node **data, size_t n)
{
size_t uniq = 0;
Node **temp = new Node*[n];
for (size_t i = 0; i < n; i++)
{
if (data[i] && !data[i]->marked)
{
data[i]->marked = true;
temp[uniq++] = data[i];
}
}
for (i = 0; i < uniq; ++i)
{
delete temp[i];
}
delete[] temp;
delete[] data;
}
The way I'd do this is have a reference counters and have a Node::deref method that would delete the node itself when reference count is 0. When iterating through the list of nodes, calling node->deref will not actually delete the object until the last Node reference in the array.
What is the proper way to delete the array1 and all its content
You show a single allocation; new Node*[n]. This allocation confers on the program the responsibility to call delete [] whatever_the_return_value_was. This is only about deleting that one allocation and not about deleting 'all its content'. If your program performs other allocations then the program needs to arrange for those responsibilities to be handled as well.
if there is a possibility of repeated pointers in the array
Well it would be undefined behavior to delete a pointer value that is not associated with any current allocation, so you have to avoid deleting the same pointer value more than once. This is not an issue of there being a single correct way, but an issue of programming practices, design, etc.
Typically C++ uses RAII to handle this stuff automatically instead of trying to do what you want by hand, because doing it by hand is really hard to get right. One way to use RAII here would be to have a second object that 'owns' the Nodes. Your array1 would then simply use raw pointers as 'non-owning' pointers. Deleting all the Nodes then would be done by letting the Node owning object go out of scope or otherwise be destroyed.
{
// object that handles the ownership of Node objects.
std::vector<std::unique_ptr<Node>> node_owner;
// your array1 object that may hold repeated pointer values.
std::vector<Node*> array1;
node_owner.emplace_back(new Node); // create new nodes
array1.push_back(node_owner.back().get()); // put nodes in the array
array1.push_back(node_owner.back().get()); // with possible duplicates
// array1 gets destroyed, but it's contents do not, so the repeated pointers don't matter
// node_owner gets destroyed and destroys all its Nodes. There are no duplicates to cause problems.
}
And the destruction does occur in linear time.
Related
This question is similar to Problem with delete[], how to partially delete the memory?
I understand that deleting an array after incrementing its pointer is not possible as it loses the track of how many bytes to clean. But, I am not able to understand why one-by-one delete/deallocation of a dynamic array doesn't work either.
int main()
{
int n = 5;
int *p = new int[n];
for(int i=0;i<n;++i){
delete &p[i];
}
}
I believe this should work, but in clang 12.0 it fails with the invalid pointer error. Can anyone explain why?
An array is a contiguous object in memory of a specific size. It is one object where you can place your data in and therefore you can only free/delete it as one object.
You are thinking that an array is a list of multiple objects, but that's not true. That would be true for something like a linked list, where you allocate individual objects and link them together.
You allocated one object of the type int[n] (one extent of memory for an array) using the operator new
int *p = new int[n];
Elements of the array were not allocated dynamically separately.
So to delete it you just need to write
delete []p;
If for example you allocated an array of pointers like
int **p = new int *[n];
and then for each pointer of the array you allocated an object of the type int like
for ( int i = 0;i < n;++i )
{
p[i] = new int( i );
}
then to delete all the allocated objects you need to write
for ( int i = 0; i < n; ++i )
{
delete p[i];
}
delete []p;
That is the number of calling of the operator delete or delete [] one to one corresponds to the number of calling operator new or new [].
One new always goes with one delete. Just as that.
In detail, when we request an array using new, what we actually do is to get a pointer that controls a contiguous & fixed block on the memory. Whatever we do with that array, we do it through that pointer and this pointer associates strictly with the array itself.
Furthermore, let's assume that you were able to delete an elemnent in the middle of that array. After the deletion, that array would fall apart and they are not contiguous anymore! By then, an array would not really be an array!
Because of that, we can not 'chop off' an array into separate pieces. We must always treat an array as one thing, not distinctive elements scattered around the memory.
Greatly simplyfyinh: in most systems memory is allocated in logical blocks which are described by the starting pointer of the allocated block.
So if you allocate an array:
int* array = new int[100];
OS stores the information of that allocation as a pair (simplifying) (block_begin, size) -> (value of array ptr, 100)
Thus when you deallocate the memory you don't need to specify how much memory you allocated i.e:
// you use
delete[] array; // won't go into detail why you do delete[] instead of delete - mostly it is due to C++ way of handling destruction of objects
// instead of
delete[100] array;
In fact in bare C you would do this with:
int* array = malloc(100 * sizeof(int))
[...]
free(array)
So in most OS'es it is not possible due to the way they are implemented.
However theoretically allocating large chunk of memory in fact allocate many smaller blocks which could be deallocated this way, but still it would deallocate smaller blocks at a time not one-by-one.
All of new or new[] and even C's malloc do exactly the same in respect to memory: requesting a fix block of memory from the operating system.
You cannot split up this block of memory and return it partially to the operating system, that's simply not supported, thus you cannot delete a single element from the array either. Only all or none…
If you need to remove an element from an array all you can do is copy the subsequent elements one position towards front, overwriting the element to delete and additionally remember how many elements actually are valid – the elements at the end of the array stay alive!
If these need to be destructed immediately you might call the destructor explicitly – and then assure that it isn't called again on an already destructed element when delete[]ing the array (otherwise undefined behaviour!) – ending in not calling new[] and delete[] at all but instead malloc, placement new for each element, std::launder any pointer to any element created that way and finally explicitly calling the constructor when needed.
Sounds like much of a hassle, doesn't it? Well, there's std::vector doing all this stuff for you! You should this one it instead…
Side note: You could get similar behaviour if you use an array of pointers; you then can – and need to – maintain (i.e. control its lifetime) each object individually. Further disadvantages are an additional level of pointer indirection whenever you access the array members and the array members indeed being scattered around the memory (though this can turn into an advantage if you need to move objects around your array and copying/moving objects is expensive – still you would to prefer a std::vector, of pointers this time, though; insertions, deletions and managing the pointer array itself, among others, get much safer and much less complicated).
I am not allowed to use Vectors specifically for this school assignment. Most of the answers I've found simply state "you should use vectors" as the most up-voted comment. While I appreciate and understand this, I'm simply restricted from using them for this assignment.
It is a C++ assignment with dynamic memory management as follows:
// property in header declaration
int numAnimals;
int capacity;
Animal** animals;
void addAnimal(Animal *newAnimal);
// class implementation
capacity = 10;
numAnimals = 0;
animals = new Animal*[capacity];
void SampleClass::addAnimal(Animal *newAnimal)
{
for (int i = 0; i < capacity; i++){
if(animals[i]){
// animal object already exists in array, move on
i++;
}else{
animals[i] = newAnimal;
numAnimals++;
break;
}
}
}
animals is a pointer to a pointer, in this case a pointer to an array of pointers to object type Animal which have yet to be created.
With the 'addAnimal' function, what I'm trying to do is add an animal object to the array by looping through the array of pointers, and if there already exists an animal object, iterate to the next index. If there is no animal, then insert that animal into the array.
I'm getting an exception thrown "read access violation" when I attempt to access a member function of an animal object in the array.
My suspicion is because:
if(animals[i]) probably isn't doing what I think it's doing, running it through the debugger I never hit the 'else' portion, so the array is still full of pointers not set to any objects when the method is complete. Therefore, when I try to access a member function, it's of an object that doesn't exist.
So, if my suspicions are correct, then what is the best way to insert a new object into an array of pointers in this fashion? They need to be pointers otherwise it automatically creates the array full of populated objects, which is not what I want.
I didn't post all of the code because I wanted to keep my problem brief, apologies I'm a new to C++ and stackoverflow in general. Yes, I know to delete[] to clear memory afterwards.
Any help is appreciated, thanks!
Since in numAnimals you keep count of the current number of animal pointers in the array, you don't need the for loop to find the first available slot to add a new animal pointer (note also that, assuming you want to use a for loop like shown in your code, you have to pay attention to properly initialize all the initial pointers in the array to nullptr).
You can just use:
// Inside SampleClass::addAnimal(Animal *newAnimal):
animals[numAnimals] = newAnimal;
numAnimals++;
Please note that you have to pay attention to not overflow your array capacity, when you insert a new animal.
So, before inserting a new animal, you have to check that there's enough room in the array, e.g.:
// Before inserting:
if (numAnimals == capacity)
{
// You ran out of capacity.
//
// 1. Allocate a new array with bigger capacity (e.g. 2X)
// 2. Copy the content from the current array to the new one
// 3. delete current array
}
As a side note:
Yes, I know to delete[] to clear memory afterwards
Note that if you call delete[] on the animals array of pointers, you release this pointer array, but not the Animal objects pointed to.
int capacity = 10;
Animal** animals = new Animal*[capacity];
This allocates ten pointers, except it does no initialization,
meaning you have essentially garbage data.
if (animals[i])
This test one of those pointers against nullptr, but since you did
no initialization, it's not very likely that it's nullptr.
You need to add a loop-pass that null out the data, right after you
allocate it:
for(int i=0; i<capacity; ++i)
animals[i] = nullptr;
There is also a bug:
if (animals[i]) {
// animal object already exists in array, move on
i++; // <- here
This is wrong, you move on twice for (int i = 0; i < capacity;i++)
The thing is "Use a vector", despite your teacher telling you otherwise, is the correct way to do it. However, if you are supposed to manage the dynamic array manually, then the best you can do is to encapsulate all that dirty memory stuff inside a class and write your own replacement for std::vector. Ie to avoid having dynamic allocations spread all over your code (especially in places that are supposed to deal with Animals and shouldnt care about manually allocating memory and the like) you should write a class that does that (and nothing else) and provides a nicer interface. I can only outline the idea here:
template <typename T>
class my_vector {
private:
T* data;
size_t size;
size_t capacity;
public:
void push_back(const T& t);
size_t size();
T& operator[](size_t index);
void resize(size_t size);
//... etc...
};
vector< int > vect;
int *int_ptr = new int(10);
vect.push_back( *int_ptr );
I under stand that every "new" needs to be followed by a "delete" at some point but does the clear() method clean this memory?
What about this method of doing the same thing:
vector< int > vect;
int int_var = 10;
vect.push_back( int_var );
From what I understand, clear() calls the variables destructors, but both vect.push_back() methods in this example push an object on the vector, not a pointer. so does the first example using an int pointer need something other than clear() to clean up memory?
The first method leaks because the vector never takes ownership of the allocated pointer. In fact, it doesn't contain a pointer at all, only a copy of the value.
The second method does not leak, as no memory is dynamically allocated (except internally in the vector -- it will handle that memory itself).
When you push_back on a vector, you add a copy of the data to the vector. Therefore, in both cases, the original data still needs to be freed. In the first case, you need to delete it; in the second, it will be "freed" by the stack pointer as it goes out of scope.
Vectors make copies on push_back. Since a pointer is 'just another variable' (but one that happens to point to memory), when you push_back an integer pointer that has been previously allocated, you copy the pointer's value into the vector, causing a potential dangling pointer, since there will be two pointers pointing at the same spot in memory.
In your first example, you would need to delete the memory manually. One strategy I've used in the past for meddling with graph classes is to have something like this (vast amounts of stuff redacted due to being at work and typing quickly):
class graph //quick-format
{
vector<node*> nodes;
add_node(node n)
{
node *temp = new node;
*temp = n;
nodes.push_back(temp)
}
~graph()
{
for(int i = 0; i < nodes.size(); i++)
delete nodes[i];
}
};
As a caveat, graph's copy semantics will have to be examined. As it stands, it will result in deleting previously-free'd memory. The advantage is that you can always have the same set of nodes hanging around. Caveat Emptor, like any direct memory usage..
However, if you simply push a non-pointer variable, there is no possibility of memory leaking from your end. Possibly the vector will leak, but... that is practically impossible at this point in the maturity of the tools.
I have a struct like this:
class Items
{
private:
struct item
{
unsigned int a, b, c;
};
item* items[MAX_ITEMS];
}
Say I wanted to 'delete' an item, like so:
items[5] = NULL;
And I created a new item on that same spot later:
items[5] = new item;
Would I still need to call delete[] to clean this up? Or won't this be needed since bounds of array items[] are known before compiling?
Is setting that pointer to NULL valid or should I be calling delete there?
You need to call delete before setting it to NULL. (Setting it to NULL isn't required, it just helps reduce bugs if you accidentally try to dereference the pointer after deleting it.)
Remember that every time you use new, you will need to use delete later on the same pointer. Never use one without the other.
Also, new [] and delete [] go together in the same way, but you should never mix new [] with delete or new with delete []. In your example, since you created the object with new (rather than new [] which would create an array of objects) you must delete the object with delete (rather than delete []).
As Kluge pointed out, you'd leak the object at index 5 like that. But this one really sounds like you shouldn't do this manually but use a container class inside Item. If you don't actually need to store these item objects as pointers, use std::vector<item> instead of that array of MAX_ITEMS pointers. You can always insert or erase vector elements in the middle as well if you need to.
In case you need to store the objects as pointers (usually if struct item is actually polymorphic, unlike in your example), you can use boost::ptr_vector<item> from Boost.PtrContainer instead.
Example:
class Items {
private:
struct item {
unsigned int a, b, c;
};
std::vector<item> items;
}
if (items.size() > 5) // (just to ensure there is an element at that position)
items.erase(items.begin() + 5); // no need to use operator delete at all
To delete an item use:
delete items[5];
after deleting the item it is advisable to set the deleted pointer to NULL, so you won't have an error if you later delete it again by mistake.
items[5] = NULL
Say I wanted to 'delete' an item, like so:
items[5] = NULL;
I know little Visual Basic, but that smells like a Visual Basic programming idiom, since "Set a = None" (or Null, I'm not sure) would delete the object pointed by a (or rather decrement its reference count, for COM objects).
As somebody else noted, you should use either:
delete items[5];
items[5] = newContent;
or:
delete items[5];
items[5] = NULL;
After delete[5], the only possible use of the pointer stored in items[5] is causing you trouble. What's worse is that it might happen to work at the beginning, and start failing only when you allocate something else over the space previously used by *items[5]. Those are the causes which make C/C++ programming "interesting", i.e. really annoying (even for who likes C like me).
Writing just delete items[5]; saves what can be an useless write, but that's a premature optimization.
Just to be clear: you refer to calling "delete[]". I think you mean delete.
I mention this because C++ has two separate operators, operator delete and operator delete[]. The latter is used for deleting arrays of objects allocated with operator new[], and does not apply in this case. You have an array of pointers to objects, which you must have initialised with repeated calls to operator new rather than a single call to operator new[].
All I'm really trying to say is: your use of delete[] is confusing and ambiguous; change it to delete.
There are a few, related, questions here:
According to the code you posted, the array itself is not allocated on the heap unless the struct is, so you don't need to delete[] the array. If you created the array with new[] you would have to delete[] it.
The code posted doesn't say how the objects being pointed to from the array are allocated. If you allocate those objects on the stack you must not delete them (then again, this is highly unlikely because your pointers will become invalid when the objects they point to fall out of scope). If you allocated them on the heap (with new) then you must delete them when they fall out of scope.
As others have already suggested, life is much easier if you use a container -- especially an STL container -- and smart pointers -- which for now means pointers out of Boost.
C++ isn't my strong suit, but I'm pretty sure you'd be leaking the memory if you set the pointer to NULL.
EDIT: The memory being leaked would be the memory being pointed to by the pointer in the array.
Setting items[5] to NULL doesn't delete the memory associated with the item, it simply sets the pointer to that item to NULL, therefore the memory is leaked.
You can delete the item by calling:
delete items[5];
Since C++ has not automatic garbage collection, you need to delete any memory you no longer need.
So I have a pointer to an array of pointers. If I delete it like this:
delete [] PointerToPointers;
Will that delete all the pointed to pointers as well? If not, do I have to loop over all of the pointers and delete them as well, or is there an easier way to do it? My google-fu doesn't seem to give me any good answers to this question.
(And yeah, I know I need to use a vector. This is one of those "catch up on C++" type assignments in school.)
Yes you have to loop over the pointers, deleting individually.
Reason: What if other code had pointers to the objects in your array? The C++ compiler doesn't know if that's true or not, so you have to be explicit.
For an "easier way," two suggestions: (1) Make a subroutine for this purpose so at least you won't have to write the code more than once. (2) Use the "smart pointer" design paradigm where you hold an array of objects with reference-counters, then the objects are deleted when the objects are no longer referenced by any code.
I agree with Jason Cohen though we can be a bit clearer on the reason for needing to delete your pointers with the loop. For every "new" or dynamic memory allocation there needs to be a "delete" a memory de-allocation. Some times the "delete" can be hidden, as with smartpointers but it is still there.
int main()
{
int *pI = new int;
int *pArr = new int[10];
so far in the code we have allocated two chunks of dynamic memory. The first is just a general int the second is an array of ints.
delete pI;
delete [] pArr;
these delete statements clear the memory that was allocated by the "new"s
int ppArr = new int *[10];
for( int indx = 0; indx < 10; ++indx )
{
ppArr[indx] = new int;
}
This bit of code is doing both of the previous allocations. First we are creating space for our int in a dynamic array. We then need to loop through and allocate an int for each spot in the array.
for( int indx = 0; indx < 10; ++indx )
{
delete ppArr[indx];
}
delete [] ppArr;
Note the order that I allocated this memory and then that I de-allocated it in the reverse order. This is because if we were to do the delete [] ppArr; first we would lose the array that tells us what our other pointers are. That chunk or memory would be given back to the system and so can no longer be reliably read.
int a=0;
int b=1;
int c=2;
ppArr = new int *[3];
ppArr[0] = &a;
ppArr[1] = &b;
ppArr[2] = &c;
This I think should be mentioned as well. Just because you are working with pointers does not mean that the memory those pointers point to was dynamically allocated. That is to say just because you have a pointer doesn't mean it necessarily needs to be delete. The array I created here is dynamically allocated but the pointers point to local instances of ints When we delete this we only need to delete the array.
delete [] ppArr;
return 0;
}
In the end dynamically allocated memory can be tricky and anyway you can wrap it up safely like in a smart pointer or by using stl containers rather then your own can make your life much more pleasant.
See boost pointer container for a container that does the automatic deletion of contained pointers for you, while maintaining a syntax very close to ordinary STL containers.
Pointers are pretty much just memory references and not spiffy little self-cleaning .net objects. Creating proper destructors for each class will make the deletion a little cleaner than massive loops throughout the code.
Let's take a (pseudocoded) real world example .Imagine that you had a class like this:
class Street
{
public:
Street();
~Street();
private:
int HouseNumbers_[];
}
typedef *Street StreetSign;
If you have an array of street signs, and you delete your array of streetsigns, that doesn't mean that you automatically delete the sreets. They re still there, bricks and mortar, they just don't have those signs pointing to them any more. You have got rid of those specific instances of pointers to the streets.
An array of pointers is (conceptually) a bit like an array of integers, it's an array of numbers representing the memory locations of various objects. It isn't the objects themselves.
If you delete[] the array of pointers, all you have done is delete an array of integers.
I think you're going to have to loop over I'm afraid.
I don't know why this was answered so confusingly long.
If you delete the array of pointers, you will free
the memory used for an array of usually ints.
a pointer to an object is an integer containing the adress.
You deleted a bunch of adresses, but no objects.
delete does not care about the content of a memory space,
it calls a destructor(s) and marks the mem as free.
It does not care that it just deleted a bunch of adresses
of objects, it merely sees ints.
That's why you have to cycle through the array first! and call delete
on every element, then you can delete the storage of the array itself.
Well, now my answer got somewhat long... .... strange... ;)
Edit:
Jason's answer is not wrong, it just fails to hit the spot. Neither
the compiler nor anything else in c(++) cares about you deleting stuff that is elsewhere
pointed to. You can just do it. Other program parts trying to use the deleted objects
will segfault on you. But no one will hinder you.
Neither will it be a problem to destroy an array of pointers to objects, when the objects
are referenced elsewhere.