There are several STL implementations, they diff from each other, but they are similar. Let's take the latest version of GCC's libstdc++ as an example:
The destructor of std::vector, all the elements in the vector are destroyed via calling std::_Destroy
~vector() _GLIBCXX_NOEXCEPT
{
std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
_M_get_Tp_allocator());
_GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC;
}
The vector has a base class:
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc>
For the memory used in the vector itself, it is destroyed in _M_deallocate in the base class, which will call the deallocate at last:
~_Vector_base() _GLIBCXX_NOEXCEPT
{
_M_deallocate(_M_impl._M_start,
_M_impl._M_end_of_storage - _M_impl._M_start);
}
void
deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__)))
{
#if __cpp_sized_deallocation
# define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp)
#else
# define _GLIBCXX_SIZED_DEALLOC(p, n) (p)
#endif
#if __cpp_aligned_new
if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
_GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n),
std::align_val_t(alignof(_Tp)));
return;
}
#endif
_GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n));
}
_GLIBCXX_OPERATOR_DELETE is a macro, we can regard it as delete