Pointers and collection of pointers in C++. How to properly delete
This is a newbe question but I have alwasy doubts with pointers in C++. This is the situation.
I have a class A which as a collection (a vector actually) of pointers of class B. This same class A has another collection of pointers to class C. Finally the objects of class B have also a collection to pointers to class C which point to the same instances the class A points to.
My question is, if I delete a member of class-C-type pointer in class B, what happens to the pointer in cl开发者_运维知识库ass A that points to the deleted instance of class C? How this situation has to be treated?
Thanks a lot in advance!
Julen.
My understanding:
A - vector<B*> - vector<C*> B - vector<C*>
From within B you are deleting all of the C*.
You need to delete each memory address separately, but only at most once.
Any pointer to a deleted address is still holding the same address, it just produces undefined behavior if you use it.
So be sure not to re-delete the B* from A that you already deleted, and be sure not to use them after they are deleted.
You may want to re-consider your hierarchy/design though.
Or consider using boost::shared_ptr if you need to store things in this way. Actually anytime you're storing a collection of pointers you should probably be using boost::shared_ptr. If you are using boost::shared_ptr you don't delete and you don't need to worry about invalidating the other pointers.
Consider using a suitable smart pointer to hold your raw pointers in the containers, instead of using straight up raw pointers, this will save you the trouble of figuring out how you are to manually delete them. These usually also support custom deallocation functions and functors, in case you need that. You could probably look into shared_ptr or weak_ptr, depending on what you need. You might also find unique_ptr to be useful, it all depends on what your requirements are.
If you delete the instances to class C from class B, then the pointers in class A still point to those addresses... resulting in undefined behavior (most likely a seg fault). You must make sure that if you delete an instance in one place, that all other references to that instance are also updated.
In your case, you'd want to clear out A's collection to class C.
An alternative would be to use smart pointers... you could have multiple references to the same instance, and the instance is only deleted when no more references exist.
If you delete the object pointed to by a pointer inside class C, actually nothing will happen to pointers to the same objects in other classes. That is they will hold the same value as before and pointed to some desallocated memory.
Several solutions :
- write code to remove pointers from other user classes when deleting from C class
- use smart pointers thus the objects pointed to will only be removed when no pointer will point to them.
I do not much like the second solution, even if it is very common, as it is sign of a poor control of your objects life cycle. You should probably reconsider your design.
If you wish to use pointer and dynamic allocation, you need to define who owns what.
In your case, deleting the C
s from the B
s is dangerous, because after the B
s have been destroyed, they have taken the C
s with them even though A
still have a reference to them.
In your situation, I would find it better to do the following:
- destroying a C does not do anything
- destroying a B does not do anything
- destroying a A destroys its collection of B's and C's
It means that A
is the owner of the memory and manages the life cycle of the objects, whereas B
s only have references to the C
s.
Also, I would advise using RAII (Resources Acquisition Is Initialization) so that the cleanup is done automatically for you:
class A
{
public:
private:
std::vector< std::unique_ptr<B> > bs;
std::vector< std::unique_ptr<C> > cs;
};
// B and C are unchanged
The use of unique_ptr
has 3 advantages:
- it clearly states who the owner of the memory is (in this case the instance of
A
) - it prevents unintended copying of the
A
instance which would wreak havoc in your desing - it simplifies the handling of memory, it's automatic, don't worry about it
I would say what you are missing are a class D.
D is the class that owns and A, B, C. If C objects are created dynamically A should create and store them, while A and B could use unmanaged pointers.
For the implementation of D a boost::ptr_vector could be a good container for the C objects if they need to be in pointer form (polymorphic objects) or a plain vector for good old objects.
It's always a good idea to set old pointers to NULL when whatever they've been pointing on has been deleted - unless you're destroying the list of pointers next.
精彩评论