So I am trying to write an implementation that mimics the std::vector the best I can.
When writing the pop_back function I came across a behavior in std::vector::pop_back that I can't understand.
Yes pop_back() just decreases the size of the vector it doesn't affect the capacity of the vector, nor does it actually clear the affected memory. However trying to read or write outside the bounds of the vector produces undefined behavior.
To be absolutely clear - as far as the code in the vector object is concerned, that 25th element is no longer there. It has been removed, and is no longer considered to be part of the vector. It can be re-used and overwritten at any time.
The fact that the object may have pre-allocated more than 24 elements worth of space for future use, and that there may still be some data in the memory immediately after the 24th element, is irrelevant.
It's exactly the same situation as when you free any dynamically allocated memory. The same data may or may not still be left in that memory, but the memory manager no longer considers that memory to be yours to use.
std::vector asks its allocator for a block of aligned uninitialized storage for its elements. It calls operator new directly to construct the element in place; when the vector is done with the element it directly calls the element's destructor.
The vector contains some code somewhat like this:
1 2 3 4 5 6 7 8
value_type* end_; // member data: points one past-the-end
// the vector stores elements in the iterator span [begin_, end_).
void pop_back()
{
--this->end_;
this->end_->~value_type(); // destroy the element
}
When value_type is a class type, this is a call to the element's destructor.
When value_type is plain int this is a call to the element's pseudo-destructor. It has no effect prior to C++20; since then it formally ends the lifetime of the int.
This feature exists primarily so that a template can destroy objects of type T without caring whether or not T happens to be a class type.