views:

91

answers:

5

Say I have 2 containers storing pointers to the same objects...

std::list<Foo*> fooList;
std::vector<Foo*> fooVec;

Lets say I remove an object from one of these containers via one if its methods, for example...

std::vector<Foo*>::iterator itr = 
  std::find( fooVec.begin(), fooVec.end(), pToObj );
fooVec.erase( itr );

CppReference says that this calls the object's destructor. Does this mean that the pointer to the object in fooList is a dangling pointer?

I'd prefer not to use reference counted pointers. How can this problem be handled?

+1  A: 

I don't think that the object's destructor will be called. The pointers in fooList should still point to valid data.

If you're referring to this link, it's talking about how calls to erase will invalidate any iterators that you might point to subsequent locations in the vector. But invalidating iterators is different from calling delete on one of the things in the vector.

Nate Kohl
+4  A: 

No.

When you remove a pointer from a container, all you've done is take that pointer value from the container, nothing is deleted. (i.e.: pointers have no destructor.)

However, it's dangerous to have pointers of things in containers. Consider:

std::vector<int*> v;
v.push_back(new int());
v.push_back(new int());
v.push_back(new int());

If you never go through the container and delete each one, you've leaked. Worse is it's not exception safe. You should use a pointer container, which will delete things it points to when they are erased. (And all get erased when the container destructs.)

In your case, though, since you are sharing a pointer in different places, I can't see an argument against shared_ptr; that's exactly what it was made for.

GMan
A: 

When you have a raw pointer to an object, no destructor is called unless you delete it.

A pattern (or is it an idiom?) that you can use for ensuring that your objects get deleted at the right time and also use pointer containers (as is needed in many algorithms) is to use a separate deque to store the actual objects. You must ensure that the deque is destroyed after any of the pointer containers. The reason you should use a deque instead of a vector is that you can add objects to a deque without invalidating pointers to previously stored objects.

ergosys
A: 

Both containers hold references to (Foo *) objects - so if a destructor is called it's the destructor of the pointer object (which probably does nothing), not that of the Foo object itself. The original object (of class Foo) is not destroyed and therefore there are no dangling references.

smichak
A: 

In you case the objects stored in the containers is a copy of your original pointer and not the original pointer. So for each Foo* that you decide to store you'll have 3 pointers (the original, one in fooList and one in fooVec), all pointing to the same location in memory. So when you call erase the delete is going to be invoked on the pointer itself not on what it points to, and the delete on pointers is a no op (they have no destructors like GMan said).

Eugen Constantin Dinca