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
Related
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.
I want a vector to hold pointers to some objects that it will own.
Here is the vector:
private:
std::vector<fppVirtual*> m_fapps;
I have created elements like this:
m_fapps.push_back(new fpp1(renderingEngine)); //fpp* are subclasses of fppVirtual
m_fapps.push_back(new fpp2(renderingEngine));
m_fapps.push_back(new fpp3(renderingEngine));
As m_fapps is a vector instance variable in another class, I want to make sure that class's destructor properly cleans up m_fapps:
for (int i=0, size=m_fapps.size();i<size;++i){
delete m_fapps[i];
}
Is this acceptable memory management technique? I assume this loop is needed since when the vector goes out of scope when its owning class is destructed, only pointers to these new objects will be removed, right?
This works (with a few caveats) but is not considered idiomatic C++, for good reason.
You should strongly consider using a vector of smart pointers (or a smart vector like boost::ptr_vector) instead, in order to avoid having to do manual memory management.
This would also give you exception safety for free, and would also avoid nasty ownership issues that occur if your outer class is copyable.
As no one gave you straight forward answer yet - yes, it is acceptable and this is the only way to free this memory, having this declaration of the vector.
This can and should be avoided, using smart pointers, as #OliCharlesworth suggested or using some other container, ponited by #BjörnPollex.
You should use boost::ptr_vector instead. The interface is the same, but it handles memory management for you. See this question for some guidelines about whether to use ptr_vector or vector<shared_ptr<>>.
I just wonder what's wrong with vector of pointer. some of my friend recommend me to use list instead of vector. will this cause a problem:
vector<Fruit*> basket;
basket.push_back(new Apple());
basket.push_back(new Orange());
vector<Fruit*> temp;
temp.push_back(basket[1]);
If I delete vector temp, do I destroy the basket[1] object too? if not, what's the problem with using vector of pointer?
If I delete vector temp, do I destroy the basket[1] object too?
No. First of all, you cannot delete temp; rather, it will get destroyed when going out of scope. And when this happens, the objects pointed by elements of the vector won't be automatically deleted.
This is, however, not a specific problem of vector: using list will not save you from this issue. The problem is rather with raw pointers. If you want the pointed objects to be automatically deallocated when the the lifetime of the last pointer which points to it ends, you should use smart pointers.
Depending on the ownership policy that your application needs, you might choose between shared_ptr and unique_ptr. The caveat with shared_ptr is that referencing cycles shall be avoided, to prevent mutually referencing objects from keeping each other alive. You may want to check weak_ptr in this respect.
Finally, unless you have a good reason for not using vector, vector should be the default choice for a container. From Paragraph 23.2.3/2 of the C++11 Standard:
The sequence containers offer the programmer different complexity trade-offs and should be used accordingly. vector or array is the type of sequence container that should be used by default. list or forward_list should be used when there are frequent insertions and deletions from the middle of the sequence. deque is the data structure of choice when most insertions and deletions take place at the beginning or at the end of the sequence.
If either of the vectors, basket or temp, are destroyed none of the Fruits are destroyed. Anything that is dynamically allocated with new must be deleted. When the vectors go out of scope, they do not delete the objects that are pointed to by their elements. If you delete an object through one vector that is pointed to in the other vector, both point at the now deleted object.
Since your vectors have automatic storage duration, you definitely must not do delete basket; or delete temp;.
It's not recommended to use raw pointers in general, especially with dynamically allocated storage that you may forget to delete. In this case, however, you do need polymorphic behaviour, which is provided by pointers. You should use a smart pointer to avoid the problems with raw pointers. Try a std::vector<std::shared_ptr<Fruit>>.
Why do I need to delete dynamically created items in vector, manually? Why wouldn't they get deleted or its destructor called when vector got deleted?
Normally something like this, but why needed ?
vector<int*> v;
for (vector<int*>::iterator it = v.begin(); it != v.end(); ++it)
{
delete *it;
}
Firstly, you store raw pointers in your vector. These pointers are just pointers. They can point anywhere. They can point to local objects, which cannot be deleted by delete. And even if they point to dynamically created objects, it doesn't necessarily mean that the user wants them to die with the vector. How is the vector supposed to know all this?
It is a matter of object ownership. Whoever owns the object is responsible for its proper and timely deletion. Ordinary raw pointers do not express ownership. That is why vector can't make any assumptions about whether the objects need to be deleted or not. If you want to tell the vector that it owns its dynamic objects, use corresponding smart pointers.
Secondly, note that your deletion technique is not necessarily safe in the general case. Some standard containers assume that the data you store in them is always valid. When you do delete on each vector element, the data in the vector becomes "invalidated" (pointers become indeterminate). This is OK with a vector. But doing something like this in a "smarter" container, like std::map or std::unordered_set for example, can and will lead to problems. Even if you destroy the container itself immediately afterwards, it is perfectly possible that the container's destruction algorithm might need to analyze (compare, hash etc.) the values of individual elements. And you just killed them all with your cycle.
Smart pointers naturally resolve this matter. But if you have to use a manual delete for raw pointers stored in a standard container, a better sequence of steps would be this
Retrieve the value of the element at i and store it in pointer p
Erase the element at i from the container
Do delete p
In the end you end up with an empty container and deleted data. Again, your approach will work for simple sequences, like std::vector or std::list, but don't do this with ordered or hashed ones.
Because the language has no way of knowing whether you need them to remain alive when you're done. What if you inserted some pointers to stack objects or something like that? Boom.
This, however, can be remedied by using a smart pointer, which will implement an appropriate policy as to automatic destruction. unique_ptr and shared_ptr are the most common and useful.
The destructor is not called because the pointer does not own the object to which it points.
In C++11, a std::unique_ptr<T> does indeed own the object to which it points. In this case, the destructor is called when the pointer is released, which is probably the behavior you want. (If you don't have a C++11 compiler but have a reasonably recent pre-C++11 compiler, unique_ptr is still available as part of TR1.)
The implementation of vector was just made to delete its memory only. Pointers do not have deconstructors. And in C++, there is no garbage collection or logic to see that it is pointers and recursive delete it.
If you would like to attend the next ISO meeting and propose that, be my guest, but for me, I just put it in an inline function:
template<class T>
public static inline void deleteVectorPointer(std::vector<T*> v)
{
for (vector<T*>::iterator i = v.begin(); i != v.end(); i++)
{
delete *i;
}
}
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.