I have a series of questions to ask.
What is the correct way to destroy a vector of pointers?
I know the vector class has the default destroyer but I do not know if the pointers change something.
An array containing object pointers in its destruction requires the simple command: Delete [] pointname?
Or do I have to do some other operation first on pointers?
A list or vector of object pointers to be emptied requires a simple command: list_name / vector_name.clear (); Or do some other operations on the pointers first?
1) What is the correct way to destroy a vector of pointers? I know the vector class has the default destroyer but I do not know if the pointers change something.
If you have manually allocated the pointers in the vector and you want to delete (deallocate and destroy) them when the vector is destroyed, you should automate it with std::unique_ptrs
{
std::vector<std::unique_ptr<int>> vec;
vec.push_back(std::make_unique<int>(1));
vec.push_back(std::make_unique<int>(2));
}
when the vector is destroyed, the integers will be destroyed as well. If you are curious as to how this works and are not familiar with code like this, read up on RAII
2) An array containing object pointers in its destruction requires the simple command: Delete [] pointname? Or do I have to do some other operation first on pointers?
If you have allocated that array with new[] then you can call delete[] on that array. Keep in mind that this will not call delete on the integers individually, it will just deallocate the memory allocated for the array. If you want to deallocate the integers as well use unique_ptr as in the above example
3) A list or vector of object pointers to be emptied requires a simple command: list_name / vector_name.clear (); Or do some other operations on the pointers first?
This will clear the container but not free the pointers. See the above two points.
In answer to your second question, using delete[] and then the name of your array of pointers is satisfactory with no additional steps. delete[] just takes the array of pointers and causes the kernel to 'realise' the memory locations they point to so other operations can 'use' (write-over the data previously in) those locations. This is all you need to do. Now other operations can request memory and the kernel is free to 'give away' those locations.
Related
I have a vector that holds a pointer to classes:
vector<Entity*> editorElements;
vector<Entity*> entities;
vector<DirectionalLight*> dirLights;
vector<PointLight*> pointLights;
vector<SpotLight*> spotLights;
This code is within my class Scene. The Scene's ctor and destructors are like so:
Scene()
{
editorElements = vector<Entity*>();
entities = vector<Entity*>();
dirLights = vector<DirectionalLight*>();
pointLights = vector<PointLight*>();
spotLights = vector<SpotLight*>();
}
~Scene()
{
delete[] &entities; // ERROR HERE
delete[] &dirLights;
delete[] &pointLights;
delete[] &spotLights;
delete[] &editorElements;
}
In the destructor I marked a line ERROR HERE. It doesn't matter which vector I put first, I always get the error.
Strange is, it was working fine until lately (wasn't touching anything within the Scene class, or in any other classes that use an instance of Scene) and all of a sudden it raised an exception:
It doesn't matter if the vectors are empty or have elements, it gives the error all the same.
I require assistance to get this sorted out.
The delete expression delete [] x is described thus:
Destroys an array created by a new[]-expression
So delete[] &entities only makes sense if &entities is an array created by a new[]-expression. Right?
But entities is a std::vector<Entity*>, not an Entity[]. You didn't create it with new[], so you must not delete it with delete[].
std::vector isn't syntactic sugar for an array, it's a template class, and std::vector<Entity*> entities isn't an array, it's an object with a constructor and destructor. That also tells us that this statement
entities = vector<Entity*>();
does nothing useful - entities is an object, so it was already default-constructed. You're just default constructing an anonymous temporary of the same type, and assigning it.
Finally, storing raw pointers in a vector is OK here as the vector isn't responsible for the objects' lifetimes. In most situations it's preferable to have the vector own the objects so you don't have to worry about deleting them manually, either directly with
vector<Entity>
or indirectly with
vector<unique_ptr<Entity>>
NB. a good guideline is: you shouldn't be using new, new[], delete or delete[] at all in user code.
Use a class object to manage your storage, because the compiler will take care of calling its constructors and destructors for you.
If you need a custom class, write one that only manages memory, so that stays decoupled from your program logic. Otherwise just use the standard library facilities like std::vector, std::array, std::unique_ptr, std::shared_ptr if you really need that ownership model, etc.
The vectors aren't newed pointers, let alone newed arrays. So you shouldn't be deleting them. If you need to call delete on the pointers stored in the vectors, you should loop over the vectors, deleting each element. But you may be better off storing smart pointers instead (e.g. std::unique_ptr<Entity>. That is if you need to store pointers to dynamically allocated objects at all.
Note that if you do end up deleting elements in the destructor, you will also need to take care of the rule of three/five.
all of a sudden it raised an exception
It is because of trying to delete something you shouldn't be deleting. The delete[] syntax is for deletion of a dynamically allocated array. But you provide it with a pointer to a std::vector instance. So the compiler takes this address for the deletion as if it was an array, which includes finding out its size and then delete the entire segment. But there's no such appropriate figure, as this is not an array, so in run-time you end up trying to delete something in a place you don't have permission to access and thus you get the assertion failure, as this is an access violation, a.k.a. segfault.
Also, vector is a class that manages its own memory. If you wanted to release entities held inside this container -- that is, the individual elements themselves, allocated dynamically -- then you should loop over them and delete each one. Conveniently, for example, using auto and a range-based for loop like this:
for (auto ptr : entities)
delete ptr;
But, in most scenarios you better save yourself this memory management overhead and opt for std::unique_ptr instead of the raw pointers:
#include <memory>
...
std::vector<std::unique_ptr<Entity>> entities;
This way you don't have to worry about freeing any memory as it will be released by the std:: unique_ptr once it's being destructed, as part of the vector's destruction.
Further, this is unnecessary and probably not what you intended to do:
entities = vector<Entity*>();
as the vector object itself is already defined (so it is existing) before this line, and all it does is create an identical new one and assign it to entities.
I have a problem about pointer and standard library use.
Let's create a new class
class Graph
{
std::vector<Edge> *edge_list;
//another way is
//std::vector<Edge> edge_list;
}
I already thought two reasons why I use pointer:
It's easy to manipulate the memory using new and delete
It can be passed by parameters easily.
However, we can pass by reference if we use vector.Then Reason 2 doesn't count.
So, Is it true if I am not strict with memory allocation, I don't need to use pointer to vector and other std container?
The implementation of std::vector contains 2 pointers:
The beginning of the allocated array
1 element after the end of the allocated array
Essentially, when you declare a vector it has no space allocated in the heap, but as you add elements this changes.
Note that std::vector manages the memory it uses, so there is no need for you to worry about new and delete (unnecessary complexity). As soon as it goes out of scope, it deallocates its memory (stack and heap).
As you said, a vector can be passed very easily by reference, which works the same way as a pointer for machine code, and it's more clear.
I read that the assign method clears the vector target indexes before assigning anything to it.Does that mean if we have a vector such as:
vector<foo*> somevector;
then the assign method would actually delete foo* before copying data to the target indexes.
then the assign method would actually delete foo* before copying data to the target indexes.
No, it will only delete pointer itself but will not delete objects which pointers pointing to.
You need to be careful when you use raw pointers in STL container. If you dynamically allocates elements in somevector, you endup leaking memory.
More practice way is to use smart pointers in STL container, dynamically allocated memory will be de-allocated in below case:
std::vector<std::unique_ptr<foo>> somevector;
No. std::vector will never call delete on stored pointers. It will simply destroy the object. In the case of a class objects with non-trivial destructors, destroying consists of calling that destructor. In the case of pointers, or any other trivially destructible object, destroying consists of doing nothing.
No, standard containers containing pointers to objects don't ever call delete on the pointers - you are responsible for doing this if/when necessary. This is why storing pointers is a bad idea.
In my code I have a vector of pointers to objects of SomeClass and a (custom comparison) vector-based priority queue that contains pointers to objects of SomeClass:
std::vector<SomeClass*> my_vector;
std::priority_queue<SomeClass*, vector<SomeClass*>, CustomCompare> my_queue;
Initially my_vector is empty and my_queue is full. Gradually my_queue is emptied into my_vector like this:
my_vector.push_back(my_queue.top());
my_queue.pop();
My question is: Will my_queue.pop() delete the memory that was allocated to the SomeClass object that was pushed back to my_vector therefore causing the element of my_vector to be a dangling pointer? Or otherwise, does the vector make a deep or a shallow copy of the object pointed to by the pointer returned by my_queue.top()?
No deletions will be made. The only thing being copied/removed/pushed_back are pointers. The objects these point to remain alive, provided they have been dynamically allocated. In that case, you will have to do the clean-up yourself.
Depending on the behaviour desired, you may want to use smart poitners to avoid manual memory management, store SomeClass objects instead of pointers, or leave things as they are and make sure to make a cleanup at the end. Bear in mind that it can be difficult to guarantee that your program will safely get to the point where the memory is released, which is one reason smart pointers are preferred over raw pointers to dynamically allocated objects.
my_queue.pop() will only delete the object stored in the queue; in this case, the pointer itself, not the object pointed by the pointer. So you are fine here.
Mandatory remark: consider using smart pointers instead of raw pointers.
Both the queue and the vector only contain pointers. Unless you use smart pointers or shared pointers neither the destructor of the queue nor that of the vector will free the memory.
No. Since they store pointers, they will copy and destroy pointers (which is a no-op). There's no magic involved. If they never store a pointer to the same object simultaneously you may want to make then store unique_ptrs if you want them to destroy the objects in the end. Alternatively you can store the actual objects in a third vector (vector<SomeClass>), and maintain the vector and queue of pointers separately.
You're storing pointer to SomeClass object everywhere, so no my_queue.pop() just removes the pointer from queue and your object is ok, and you will store a copy of pointer to vector, not a deep copy.
I am having some difficulty understanding how containers are implemented in C++. Specifically, how can I deal with data allocated on the stack vs data allocated on the heap. For instance:
vector<int> VectorA;
VectorA.push_back (1);
VectorA.push_back (2);
VectorA.push_back (3);
vector<int*> VectorB;
VectorB.push_back (new int (1));
VectorB.push_back (new int (2));
VectorB.push_back (new int (3));
How does one deal with making sure the integers in VectorB are deleted properly. I remember reading somewhere that std::vector only calls the destructor and doesn't actually delete anything. Also, if I wanted to implement my own LinkedList class, how would I deal with this particular problem?
The ideal way to deal with the problem is by using Smart Pointers as elements of your container instead of raw pointers.
Otherwise you have to manually do the memory management yourself.
The objects stored in the vector are stored on the heap anyway (in space allocated by the vector).
There is very little advantage in allocating the objects separately (option B), unless you intend to manage them somehow outside of the vector. In that case the vector can just destroy the pointers it stores, and trust the real owner to destroy the objects themselves.
The short answer is that most don't deal with such things at all. The standard containers (e.g., std::vector) don't store the original object at all -- they store a copy of the object. They manage the storage for their own copy, and it's up to you to manage the storage for the original.
In the case of storing pointers, you're basically taking responsibility for managing the storage pointed to by the pointer. The container is still making (and managing the storage for) a copy, but it's just a copy of the pointer, not the object to which it refers. That's up to you to deal with.