How to clean up a vector/map properly? - c++

If I have a vector<string*> *vect or a map<pair<string*, int*>, string*> *map,
how to clean up everything (including all object the vector/map contains)?
(Everything (vector, map, contents, string, ints) is allocated with new)
Is this enough:
delete vect;
delete map;

No, you must iterate through the vector/ map, remove and delete its items one by one (which, as #SB pointed out, may require disposing of their members recursively).
(You could get away by simply deleting the items, if you are absolutely sure no one will access the vector elements anymore before the vector gets deleted - but it is still safer to remove each item before deleting it. This ensures program correctness at any point, eliminating the possibility for subtle bugs and easing maintenance in the long term.)
By the way this is one of the reasons why it is recommended to store smart pointers in collections, instead of raw pointers.

You really should consider using smart pointers.
vector<boost::shared_ptr<std::string> >* some_vector = new std::vector<boost::shared_ptr<std::string> >;
some_vector->push_back(boost::shared_ptr<std::string>("Hello World !"));
delete some_vector; // This will delete the contained std::string's as well
some_vector = NULL;
Basically, a smart pointer takes care of the life-cycle of the pointed data. They can even do much more (such a counting references, and so on) but I suggest you read this page to learn more about the different types of smart pointers.
You can even specify a custom "freeing" function to use, instead of the default (delete).

No, you must manually iterate over each container and call delete on the pointers it contains. The vector didn't allocate that memory, so it's not going to clean it up for you.
If you use smart pointers then the pointer itself will handle deallocating it's memory. Otherwise, you must balance your manual allocation with manual deallocation.

You may want to consider Boost Pointer Container. It handles all the cleaning up and, in my experience, normal containers can seamlessly (meaning without breaking code) be replaced by these ones.
A pointer container expresses ownership of the contained objects by the container, which is what you have here (otherwise you wouldn't have to clean it up).
A container of smart-pointers is different, because the objects may live longer than the container. Also, there may be a small performance-penalty when using smart-pointers, but that really depends on the size of your containers and the type of operations you perform on them.

Related

Why is using vector of pointers considered bad?

Recently I've met with opinion that I shouldn't use vector of pointers.
I wanted to know - why I cant?
For example if I have a class foo it is possible to do this:
vector <foo*> v;
v.push_back(new foo());
I've already seen some people down voting such practices, why is that?
Storing plain pointers in a container can lead to memory leaks and dangling pointers. Storing a pointer in a container does not define any kind of ownership of the pointer. Thus the container does not know the semantics of desctruction and copy operations. When the elements are being removed from the container the container is not aware how to properly destroy them, when a copy operation is performend no ownership semanctics are known. Of course, you can always handle these things by yourself, but then still a chance of human error is possible.
Using smart pointers leaves the ownership and destruction semantics up to them.
Another thing to mention is that containers are divided into non-intrusive and intrusive contaiers - they store the actual provided object instead of a copy so it actually comes down to a collection of pointers. Non intrusive pointers have some advantages, so you can't generalize that pointers in a container is something that should be avoided in all times, still in most cases it is recommended.
Using an vector of raw pointers is not necessary bad style, as long as you remember that the pointers do not have ownership semantics. When you start using new and delete, it usually means that you're doing something wrong.
In particular, the only cases where you should use new or delete in modern C++ code is when constructing unique_ptr's, or constructing shared_ptr's with custom deleters.
For example, assume that we have an class that implemented an bidirectional Graph, a Graph contains some amount of Vertexes.
class Vertex
{
public:
Vertex();
// raw pointer. No ownership
std::vector<Vertex *> edges;
}
class Graph
{
public:
Graph() {};
void addNode()
{
vertexes.push_back(new Vertex); // in C++14: prefer std::make_unique<>
}
// not shown: our Graph class implements a method to traverse over it's nodes
private:
// unique_ptr. Explicit ownership
std::vector<std::unique_ptr<Vertex>> vertexes;
}
void connect(Vertex *a, Vertex *b)
{
a->edges.push_back(b);
b->edges.push_back(a);
}
Notice how i have an vector of raw Vertex * in that Vertex class? I can do that because the lifetime of the Vertexes that it points to are managed by the class Graph. The ownership of my Vertex class is explicit from just looking at the code.
An different answer suggests using shared_ptr's. I personally dislike that approach because shared pointers, in general, make it very hard to reason about the lifetime of objects. In this particular example, shared pointers would not have worked at all because of the circular references between the Vertexes.
Because the vector's destructor won't call delete on the pointers, so it's easy to accidentally leak memory. A vector's destructor calls the destructors of all the elements in the vector, but raw pointers don't have destructors.
However, you can use a vector of smart pointers to ensure that destroying the vector will free the objects in it. vector<unique_ptr<foo>> can be used in C++11, and in C++98 with TR1 you can use vector<tr1::shared_ptr<foo>> (though shared_ptr has a slight overhead compared to a raw pointer or unique_ptr).
Boost also has a pointer container library, where the special delete-on-destruction behavior is built into the container itself so you don't need smart pointers.
One of the problems is exception-safety.
For example, suppose that somewhere an exception is thrown: in this case, the destructor of std::vector is called. But this destructor call does not delete the raw owning pointers stored in the vector. So, the resources managed by those pointers are leaked (these can be both memory resources, so you have a memory leak, but they could also be non-memory resources, e.g. sockets, OpenGL textures, etc.).
Instead, if you have a vector of smart pointers (e.g. std::vector<std::unique_ptr<Foo>>), then if the vector's destructor is called, each pointed item (safely owned by a smart pointer) in the vector is properly deleted, calling its destructor. So, the resources associated to each item ("smartly" pointed to in the vector) are properly released.
Note that vectors of observing raw pointers are fine (assuming that the lifetime of the observed items exceeeds that of the vector). The problem is with raw owning pointers.
I will talk specifically about a vector of pointers that's responsible for managing the lifetime of the pointed objects, because that's the only case where a vector of pointers is clearly a questionable choice.
There are much better alternatives. Specifically:
std::vector<std::shared_ptr<foo>> v;
and
std::vector<std::unique_ptr<foo>> v;
and
boost::ptr_vector<foo> v; // www.boost.org
The above versions tell the user how the lifetime of the objects is taken care of. Using raw pointers instead can possibly lead to the pointers being deleted either more or less than once, especially if the code is modified over time, or if exceptions become involved.
If you use an interface like ´shared_ptr´ or ´unique_ptr´, this self-documents the lifetime management for the user. When you use raw pointers you have to be clearly document how you handle the lifetime management of the objects, and hope that the right people read the documentation at the right time.
The benefits of using vectors of raw pointers are that you have more flexibility in how taking care of lifetime management, and that you can possibly get rid of some performance and space overhead.
There is absolutely no problem in using a vector of pointers. Most here are suggesting smart pointers, but I just have to say, there is no problem with using a vector of pointers without smart pointers. I do it all the time.
I agree with juanchopanza that the problem is your example is the pointers come from new foo(). In a normal completely-valid use case, you might have the objects in some other collection C, so that the objects will automatically get destroyed when C is destroyed. Then, in doing in the process of doing in-depth operations on the objects in C, you might create any number of other collections containing pointers to the objects in C. (If the other collections used object copies that would be time and memory wasteful, while collections of references is expressly forbidden.) In this use case, we never want to destroy any objects when a collection of pointers is destroyed.

RAII approach for a container of containers?

Assuming that my T is a vector typedef std::vector<ofSomething> T; ( it's usually a vector around 4-5 MB, it's expensive to recreate and store as it is in a data structure )
so, considering :
pointers
references
smart pointers
I have to create a container of vectors, or I have to put all this vectors together somehow, I'm wondering what is the best approach according to the RAII philosophy .
std::container<T*>
or
std::container<T&>
or
std::container<unique_ptr<T>>
with pointers I need to call the destructor explicitly, and this doesn't really look and sound like RAII at all.
with references it's basically the same as with pointers.
with smart pointers I get what I want if I delete or just "drop" the object representing the smart pointer.
Is a collection of smart pointers a really good idea for a container of containers ? I don't know, they are here to express ownership not for automatic memory management, it sounds like I'm doing something wrong with the wrong philosophy, at the same time I have multiple big containers to handle until they "expire" or they are not needed anymore.
What you suggest ?
If you want a vector of vectors, and you want RAII, then the answer is so simple:
std::vector<std::vector<T>> v;
… no references or pointers in sight.
If you're concerned about the inner containers being moved around as the outer vector grows, flatten it:
std::vector<T>
and wrap the indexing, so that i = x*W+y.
As you say, with a raw pointer you'll need to do your own memory management - scratch that. You can't store a reference in a standard container because allocators are not defined for reference types, and you'll still need to allocate your objects on the heap somehow - scratch that. The std::unique_ptr will perform memory management for you and actually compile - this wins... from your choices.
But what about std::container<T>? This will also work fine and not have any issues with manual memory management. It will also benefit from move semantics, so you don't need to worry about the vectors being copied. You also avoid an extra level of indirection.
Obviously using a std::unique_ptr restricts what you can do with your container. If you need to be able to copy it and/or its items, you'll want std::shared_ptr instead.

Memory allocation of values in a std::map

I've had some experience in C++ from school works. I've learned, among other things, that objects should be stored in a container (vector, map, etc) as pointers. The main reason being that we need the use of the new-operator, along with a copy constructor, in order to create a copy on the heap (otherwise called dynamic memory) of the object. This method also necessitates defining a destructor.
However, from what I've read since then, it seems that STL containers already store the values they contain on the heap. Thus, if I were to store my objects as values, a copy (using the copy constructor) would be made on the heap anyway, and there would be no need to define a destructor. All in all, a copy on the heap would be made anyway???
Also, if(true), then the only other reason I can think of for storing objects using pointers would be to alleviate resource needs for copying the container, as pointers are easier to copy than whole objects. However, this would require the use of std::shared_ptr instead of regular pointers, since you don't want elements in the copied container to be deleted when the original container is destroyed. This method would also alleviate the need for defining a destructor, wouldn't it?
Edit : The destructor to be defined would be for the class using the container, not for the class of the objects stored.
Edit 2 : I guess a more precise question would be : "Does it make a difference to store objects as pointers using the new-operator, as opposed to plain values, on a memory and resources used standpoint?"
The main reason to avoid storing full objects in containers (rather than pointers) is because copying or moving those objects is expensive. In that case, the recommended alternative is to store smart pointers in the container.
So...
vector<something_t> ................. Usually perfectly OK
vector<shared_ptr<something_t>> ..... Preferred if you want pointers
vector<something_t*> ................ Usually best avoided
The problem with raw pointers is that, when a raw pointer disappears, the object it points to hangs around causing memory and resource leaks - unless you've explicitly deleted it. C++ doesn't have garbage collection, and when a pointer is discarded, there's no way to know if other pointers may still be pointing to that object.
Raw pointers are a low-level tool - mostly used to write libraries such as vector and shared_ptr. Smart pointers are a high-level tool.
However, particularly with C++11 move semantics, the costs of moving items around in a vector is normally very small even for huge objects. For example, a vector<string> is fine even if all the strings are megabytes long. You mostly worry about the cost of moving objects if sizeof(classname) is big - if the object holds lots of data inside itself rather than in separate heap-allocated memory.
Even then, you don't always worry about the cost of moving objects. It doesn't matter that moving an object is expensive if you never move it. For example, a map doesn't need to move items around much. When you insert and delete items, the nodes (and contained items) stay where they are, it's just the pointers that link the nodes that change.

How should I retain a pointer to an std::unique_ptr?

I have a vector:
std::vector<std::unique_ptr<myClass>> vec;
//filling the vector
vec.push_back(std::unique_ptr<myClass>(new myClass()));
vec.push_back(std::unique_ptr<myClass>(new myClass()));
vec.push_back(std::unique_ptr<myClass>(new myClass()));
I need a handle to a specific instance of myClass that doesn't need to worry about ownership, e.g:
std::unique_ptr<myClass>& myInstance;
The problem is that myInstance will need point to different instances of myClass during runtime.
I know I could use an std::shared_ptr, but I want to keep them std::unique_ptr's so if something already initialized is added the ownership is transferred to vec.
How should I retain a pointer to an std::unique_ptr?
Additionally, would it considered bad practice to use a raw pointer here? The pointer won't need to manage any resources, but I don't want my code to get confusing.
The comments to your post indicate that using a raw pointer in a "non-owning" capacity should be OK. I tend to concur with that general sentiment, but your case needs further examination.
For your situation you should not use "a pointer to an std::unique_ptr". The problem is that when you (or a maintenance programmer) adds to the vector, the vector could reallocate. If it does, your pointer is invalidated and must not be used.
One option would be to use the index into the vector instead of a pointer. This has the problem of breaking if you ever delete or rearrange entries in the vector.
Another, more robust, option is to use a pointer direct to the actual myClass object rather than the unique_ptr that owns it. This option is enabled by your use of a vector of unique_ptrs of objects instead of the more usual vector of objects.

Memory management and C++ container classes

I'm having some trouble using the std container classes (list, map etc.) in C++. The problem seems to be to do with removing items for the containers. I'm trying to store pointers to objects within a container, and then when I want to remove the item from the container I use either erase or remove. When I do this, does the container actually delete the object that was in the container, or simply remove the pointer from the container?
What I'm hoping is that it just removes the pointer, because I'm using the containers to group objects and and object may be in more than one group, so I don't want it to be deleted when it's removed from a container!
Thanks!
When I do this, does the container actually delete the object that was in the container, or simply remove the pointer from the container?
The latter.
... so I don't want it to be deleted when it's removed from a container!
This is in fact what happens, but I'd still like to point out std::shared_ptr, which can make pointer/container interactions a lot easier.
When I do this, does the container actually delete the object that was in the container, or simply remove the pointer from the container?
Standard Library containers do not take the responsibility of deallocating dynamic memory of pointer elements. You will have to take care of deallocating the dynamic memory yourself, If you are storing a raw pointer in the container.
This is where power of the RAII concept in C++ comes to your rescue. You can use a Smart pointer instead of raw pointers inside the container and once you do that the deallocation will be implicitly handled by the smart pointer instead of you having the overhead of explicitly handling the memory management.
There are a number of smart pointers available and I purposefully restrained myself from suggesting a particular smart pointer because it will specifically depend on the ownership and the lifetime of the object involved.Check the link and choose a appropriate smart pointer as per your requirement.
Effective STL by Scott Meyer will give you the answer about storing raw pointer in container classes.
If you don't want to use smart_pointers or other similar things, but storing raw pointer, you have to explicitly delete it if you want to clear the memory associated.
When allocating, for example a std::vector then before clearing it, you have to delete each element of it manually.
std::vector<int*> v(10;
for (int i=0; i<10; i++)
v.at(i) = new int;
wrong way
v.clear(); // !!! MEMORY LEAK
the correct way is
for (int i=0; i<10; i++)
delete v.at(i);
and then
v.clear();
comipler doesn't remove object which placed in heap-memory