We have a scenario where we need to create an
std::vector<std::vector<float>> data;
because the vectors aren't at all the same length.
When data gets freed, does every vector inside data also free up its space?
All of the standard library types implement RAII appropriately. That is, any kind of internal dynamic allocation that they perform will be cleaned up automatically by the time the object is destroyed. You never need to worry about it.
In the case of the standard containers, like std::vector, it will automatically ensure that each of its elements is destroyed. Of course, if the elements of the std::vector are themselves std::vectors, they will in turn destroy their elements. Everything is automatic.
You may have seen examples in which you have a std::vector<T*> and the T objects were then allocated manually using new. It's important to realise here that the elements of the vector are not the T objects, but T* objects. The pointers will be cleaned up automatically. Since you manually allocated the T objects, you need to manually deallocate them. (As #Veritas says in the comments, in this case you should prefer using smart pointers)
Yes
Whenever The "Scope" of 'data' ends , The destructor will be automatically called and memory that was allocated for'data' will be freed.
Whenever the destructor is called for a vector then the destructor each of its elements will be called.
Suppose for vector a(5)
Here destructors of a[0],a[1],... will be called.
Similarly in the above case vector< vector > x;
destructors of x[0],x[1] will be called consecutively..
But here each element x[i] is again a vector so again destructors of x[i][0],x[i][1]... will be called..
In this way all elements are destroyed Recursively..
Related
In The C++ Programming Language, there is the following example (section
3.2.4).
unique_ptr<Shape> read_shape(istream& is);
void user()
{
vector<unique_ptr<Shape>> v;
while (cin)
v.push_back(read_shape(cin));
draw_all(v);
// call draw() for each element
rotate_all(v,45);
// call rotate(45) for each element
} // all Shapes implicitly destroyed
Stroustrup is trying to make the point that by using unique_ptrs, one
doesn't have to manually loop through the vector and delete all
Shapes. I'm having trouble understanding why this is true.
The way I understand smart pointers is that if a smart pointer sptr is
allocated on the stack, with something like
std::unique_ptr<Shape> sptr(new Shape());
you don't need to call delete on it at the end of the function. However,
from what I can tell in the above example those smart pointers are not
on the stack, they're put inside the data array of v, which is on the
heap.
Whether the unique_ptr is on the stack or the heap doesn't really matter. What matters is that it will automatically call delete on the target pointer when its destructor runs.
When the vector goes out of scope, the vector's destructor runs. That destroys all contained elements (calling their destructors in the process) and then deallocates its heap buffer.
This is what destructors are for. You don't see the "manual loop" that destroys the unique pointers because that loop is within the destructor of the vector. All containers destroy their elements.
When the destructor for std::vector runs it calls the destructor for each object it contains. The destructor for std::unique_ptr calls delete/delete[] on the pointer it wraps, so all of the memory that was allocated will be cleaned up correctly.
When a std::unique_ptr itself is destructed or reset, it calls delete or delete[] (or a custom deleter that you specify) on the object/array that it is currently holding a pointer to.
If the std::unique_ptr is created in automatic memory, such as the stack, it is destructed when it goes out of scope.
If the std::unique_ptr is created in dynamic memory, such as the heap, it is destructed when delete is called on it.
A container owns the elements that it stores. It knows whether its elements are of a type that defines a destructor or not, and if so then it will call that destructor on each element when needed, such as when removing individual elements from the container, or when the container itself is destructed or cleared.
So, if you have a container of std::unique_ptr elements, they will be destructed for you when appropriate, which in turn will destruct the things that they are pointing at.
Yes, if you create something on the heap, you have to delete it yourself. Unlike automatic variables (those on the stack, even though the standard doesn't actually mandate the existence of a stack), the lifetime (scope) of those objects can continue across function return boundaries.
However, the vector here is not on the heap - it's actually an automatic variable that will undoubtedly store some of its information on the heap (the array holding the vector elements, most likely), but the variable itself is not.
That means, when it goes out of scope on exit from user(), the destructor is called for it. That destructor is smart enough to free the heap-specific stuff for the vector itself, and call the destructor for each element in the vector.
And, of course, destructing each of those elements may cause further destructors to be called. If one of those elements being destructed is a smart pointer, it will know that it needs to release its hold on the underlying pointer, by either freeing it or decrementing a count to say it has no further interest in it.
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.
If STL map is declared locally inside a function, is it necessary to clear the map before the function exits? If not cleared, does it cause memory leak?
No. Standard containers do not need to be cleared before destruction as resources are automatically released.
Note however that if your std::map or std::vector contains raw pointers to dynamically allocated memory then this memory must be taken care of.
In other words the destruction of a raw pointer doesn't deallocate the memory pointed to, therefore code like:
void foo() {
std::map<std::string, int *> mymap;
mymap["mykey"] = new int[100];
...
}
will not leak the key, but it will leak the dynamically allocated 100 integers.
If the map contains other containers then everything will be fine; for example:
void foo() {
std::map<std::string, std::vector<int> > mymap;
mymap["mykey"].resize(100);
...
}
doesn't leak memory.
All this sums up to; always use containers or smart pointers; only use dynamically allocated objects pointed by raw pointers if you really really need to.
Does STL 'map' declared locally inside a function need to be cleared when the function exits?
No, the destructors of standard library containers* take care of clearing up their own resources. Otherwise they would be quite unusable.
* The same applies to the STL, but I believe you are referring to the C++ standard library
That depends on whether the STL map was created on heap or on stack in the function.
If the STL map was created on heap it needs to be deleted. If the STL map is created on stack, the destructor for the map shall be called automatically during stack unwinding.
Also note that, if the STL container holds pointers, then the memory pointed by these pointers will have to be freed explicitly. Here, the destructor of STL will only free the memory allocated to hold the pointers; but not the memory pointed by the held pointers.
For STL containers holding copies (of objects or other basic data types), the destructor for these objects shall be called by the STL destructor before the STL itself is cleaned up during stack unwinding.
From the vector docs it would appear that the proper way to completely deallocate a vector of values to which you have a class member pointer such as:
std::vector<MyObject>* mvMyObjectVector_ptr;
...
//In the class constructor:
mvMyObjectVector_ptr = new std::vector<MyObject>();
would be to invoke the following, in order, in the class's destructor implementation
mvMyObjectVector_ptr->clear();
delete mvMyObjectVector_ptr;
However, this appears to be leading to SIGABRT 'pointer being freed was not allocated' errors. Is the above idiom the correct way to completely deallocate the memory held at the address pointed to by a pointer to a vector (if it is, I assume my errors are coming from something else)? If not, what is the correct way?
Yes, it is correct, provided mvMyObjectVector_ptr has been allocated using new.
Additionally, MyObject needs to satisfy certain requirements before it can be used with std::vector.
The call to clear() is redundant and can be omitted.
Some likely reasons for the SIGABRT include:
mvMyObjectVector_ptr hasn't been allocated using new;
MyObject violates the Rule of Three;
the class the contains the vector violates the Rule of Three.
I don' think your problem lies in the code you have shown us.
This line:
//In the class constructor:
suggests you are using this inside a class and not implementing the rule of three correctly.
A better idea is not to use a pointer to a vector.
Just declare it as a normal automatic member.
class MyClassContainingVector
{
public:
std::vector<MyObject> mvMyObjectVector;
// ^^^^^ notice no pointer.
};
Now it will be created and destroyed correctly and automatically.
Neither your constructor or destructor will need any code to manage this object.
Yes, dynamically allocating a std::vector object by calling new and invoking its destruction by calling delete will result in memory that has been internally used for holding its elements being freed.
However it would be much simpler and more reliable to follow RAII idiom and use an object with automatic storage duration:
{
std::vector<MyObject> myVector;
...
} // <-- memory is freed here
when execution leaves this scope (note that it could be also caused by exception being thrown etc.), it is guaranteed that myVector object will be destructed and memory will be freed.
Vectors usually shouldn't be held as dynamically allocated pointers. They should be just member variables of your class, in most situations (though there are always exceptions). If they are pointers allocated by 'new', and simple 'delete' should work.
Vectors handle memory allocation for you, so you don't have to. However, if you want to truly free all the storage memory held in a vector, even if it's on the stack, there's a new function for that.
Because vector.reserve() only expands memory, but never shrinks it, in C++11, a new function was added for the purpose of freeing the reserved memory: vector.shrink_to_fit(). Implementations and free to do what they want with it, but you're basically asking the implementation to free the memory, so they should answer the request in a reasonable way.
You can truly clear a vector by going like this:
vector.clear(); //Erases the elements.
vector.shrink_to_fit(); //Erases the memory no longer needed by the elements.
The reasons why vectors hold onto their memory is for performance reasons, so you should only do this if you actually understand why they have memory in reserve, and are willing to deal with (or know you won't have to deal with) any performance hits that result from micro-managing the memory.
Suppose a std::vector is defined in a function (i.e., on stack) and the vector is re-allocated (like by inserting data). Will any part of the vector be in heap? if yes, will it leave any garbage in heap when done executing the function? Thanks.
Will any part of the vector be in heap?
Yes: all of the elements in a std::vector are stored in a heap-allocated array.
Will it leave any garbage in heap when done executing the function?
No. The std::vector container, like all of the Standard Library containers, is responsible for cleaning up any objects that it creates.
Note, however, that if you dynamically allocate objects (e.g., using new) and store them in a container, then you are responsible for destroying those objects. To avoid having to clean things up yourself, you should avoid explicitly dynamically allocating objects wherever possible and use smart pointers everywhere else.