Destructors when calling std::vector::erase()

Started by
14 comments, last by iMalc 14 years, 3 months ago
Just a quick question to check I'm not going insane: Am I correct in observing that, when you delete an element from a vector using erase(), the destructor of the erased element will not be called, but the destructor of the last element in the vector will? Perhaps it's implementation-dependent, but I guess the reason it's happening is that all the elements after the erased one are being shifted down, so the destructor is called on the final, "hanging" element. I can't find this documented anywhere, but it seems like something that should be warned about since the naive expectation would be for the destructor of the "erased" element to be called. Can anyone confirm that what I'm experiencing is the expected behaviour?
Advertisement
It shouldn't matter if the destructor for the erased element is called. Why do you think it matters?

I'd think it's totally reasonable to expect that when removing an element from a container, the next element is simply assigned to it

If this matters, maybe your assignment operator isn't written correctly
Standard containers expect the value types to be copyable and assignable. If these operations work properly, it shouldn't make any difference to you, which object had its destructor called.
If your class obeys the contract expected by the container, then it shouldn't matter which element has its destructor called on it.
It matters if the destructor dynamically deallocates memory.

class SomeClass{ SomeOtherClass * foo; SomeClass::SomeClass() foo = new SomeOtherClass; SomeClass::~SomeClass() delete foo;};


If you use vector::erase to remove a SomeClass object from a vector, and its destructor is not called, the memory pointed to by foo will not be deallocated. Additionally, the final element in the vector will have its destructor called, so foo will be unexpectedly freed.

I suppose the simplest way round this is to use vectors of pointers for non-POD types, and delete them manually.
If you class leaks when put into a vector, then it doesn't obey the contract std::vector expects. Types stored in a vector must be copyable. The vector will make copies or perform assignments when it is adding elements or erasing them.

Your class should have a correct copy construcor and assignment operator. If not, you should explicitly disable them.

If making copies of your class is expensive, an alternative is a smart vector or a vector of smart pointers.
Quote:Original post by visitor
Standard containers expect the value types to be copyable and assignable. If these operations work properly, it shouldn't make any difference to you, which object had its destructor called.


That'll be the problem, then: I can either have copy and assign methods which reallocate and deallocate large chunks of memory, or just use vectors of pointers. Think I'll go with pointers.
Quote:Original post by myers
Quote:Original post by visitor
Standard containers expect the value types to be copyable and assignable. If these operations work properly, it shouldn't make any difference to you, which object had its destructor called.


That'll be the problem, then: I can either have copy and assign methods which reallocate and deallocate large chunks of memory, or just use vectors of pointers. Think I'll go with pointers.


But then the objects are no longer contiguous in memory, and you might as well be using a list instead of a vector.

If you use a smart pointer like boost::shared_ptr to the dynamic memory each object points to, the ref counting will cause the pointers to be copied down and the only dynamic memory that will end up getting freed would belong to the element erased

That will give you better expression of ownership semantics and can avoid your having to reallocate and copy the owned dynamic memory on assignment
Quote:Original post by c_olin
Quote:Original post by myers
Quote:Original post by visitor
Standard containers expect the value types to be copyable and assignable. If these operations work properly, it shouldn't make any difference to you, which object had its destructor called.


That'll be the problem, then: I can either have copy and assign methods which reallocate and deallocate large chunks of memory, or just use vectors of pointers. Think I'll go with pointers.


But then the objects are no longer contiguous in memory, and you might as well be using a list instead of a vector.


Using a vector lets me retain random access, though.

This topic is closed to new replies.

Advertisement