In the C++ stdlib distribution included with Mac OS X (Darwin 10.5.0 i386), the implementation of std::vector::erase() from vector.tcc lines 106-116 is shown here: template<typename _Tp, typename _Alloc> typename vector<_Tp, _Alloc>::iterator vector<_Tp, _Alloc>:: erase(iterator __position) { if (__position + 1 != end()) std::copy(__position + 1, end(), __position); --this->_M_impl._M_finish; this->_M_impl.destroy(this->_M_impl._M_finish); return __position; } Note that "destroy()" will be called for the element that is *last* in the vector prior to the call to this erase(), instead of being called for the element pointed to by __position. I believe this is incorrect -- I think it should instead call destroy() for the element pointed to by __position. For simple POD types, this isn't that big of a deal, but for classes where the destructors have side effects (such as smart pointers), it can be critical. The following code illustrates the problem: #include <vector> #include <iostream> class MyClass { int m_x; public: MyClass(int x) : m_x(x) { } ~MyClass() { std::cerr << "Destroying with m_x=" << m_x << std::endl; } }; int main(void) { std::vector<MyClass> testvect; testvect.reserve(8); testvect.push_back(MyClass(1)); testvect.push_back(MyClass(2)); testvect.push_back(MyClass(3)); testvect.push_back(MyClass(4)); testvect.push_back(MyClass(5)); std::cerr << "ABOUT TO DELETE #3:" << std::endl; testvect.erase(testvect.begin() + 2); std::cerr << "DONE WITH DELETE." << std::endl; return 0; } When I compile this with g++ version 4.2.1 (no command line arguments) on my Mac, it produces the following when I run it: Destroying with m_x=1 Destroying with m_x=2 Destroying with m_x=3 Destroying with m_x=4 Destroying with m_x=5 ABOUT TO DELETE #3: Destroying with m_x=5 DONE WITH DELETE. Destroying with m_x=1 Destroying with m_x=2 Destroying with m_x=4 Destroying with m_x=5 Note that the key line after the "ABOUT TO DELETE #3" message shows that the destructor was actually called for the fifth thing I added. Importantly, the destructor for #3 is never called!!
It appears that the version of erase that takes a range (two iterators) also has a similar problem.
(In reply to comment #0) > In the C++ stdlib distribution included with Mac OS X (Darwin 10.5.0 i386), the GCC 4.2 is no longer maintained, you should either try a current release or report bugs to Apple. > implementation of std::vector::erase() from vector.tcc lines 106-116 is shown > here: > > template<typename _Tp, typename _Alloc> > typename vector<_Tp, _Alloc>::iterator > vector<_Tp, _Alloc>:: > erase(iterator __position) > { > if (__position + 1 != end()) > std::copy(__position + 1, end(), __position); > --this->_M_impl._M_finish; > this->_M_impl.destroy(this->_M_impl._M_finish); > return __position; > } > > > Note that "destroy()" will be called for the element that is *last* in the > vector prior to the call to this erase(), instead of being called for the > element pointed to by __position. I believe this is incorrect -- I think it > should instead call destroy() for the element pointed to by __position. No, the element at position is overwritten by the call to std::copy() > For > simple POD types, this isn't that big of a deal, but for classes where the > destructors have side effects (such as smart pointers), it can be critical. > > The following code illustrates the problem: > > > #include <vector> > #include <iostream> > > class MyClass > { > int m_x; > public: > MyClass(int x) : m_x(x) { } > ~MyClass() > { > std::cerr << "Destroying with m_x=" << m_x << std::endl; > } > }; > > int main(void) > { > std::vector<MyClass> testvect; > testvect.reserve(8); > testvect.push_back(MyClass(1)); > testvect.push_back(MyClass(2)); > testvect.push_back(MyClass(3)); > testvect.push_back(MyClass(4)); > testvect.push_back(MyClass(5)); > > std::cerr << "ABOUT TO DELETE #3:" << std::endl; > > testvect.erase(testvect.begin() + 2); > > std::cerr << "DONE WITH DELETE." << std::endl; > > return 0; > } > > > When I compile this with g++ version 4.2.1 (no command line arguments) on my > Mac, it produces the following when I run it: > > Destroying with m_x=1 > Destroying with m_x=2 > Destroying with m_x=3 > Destroying with m_x=4 > Destroying with m_x=5 > ABOUT TO DELETE #3: > Destroying with m_x=5 > DONE WITH DELETE. > Destroying with m_x=1 > Destroying with m_x=2 > Destroying with m_x=4 > Destroying with m_x=5 As you can see, the results are correct, the vector contains {1,2,4,5} > Note that the key line after the "ABOUT TO DELETE #3" message shows that the > destructor was actually called for the fifth thing I added. Importantly, the > destructor for #3 is never called!! Doesn't matter, the requirements of std::vector do not say that must happen