I couldn't find an exact answer to this question and hence posting here.
When I think of vector, it needs to build objects in a contiguous memory location. This means that vector keeps memory allocated and have to do an in-place construction (=placement new) of objects being pushed into it. Is this a valid assumption? Also, does this mean the container is manually invoking the destructor rather than calling delete? Are there any other assumptions that I am missing here? Does this mean I can assume that even a custom written new for the object may not be invoked if I chose to write?
Also it makes sense for a list to use a new and delete as we don't need the continuous memory guarantee. So, is this kind of behavior is what drives how allocators behave? Please help.
Thanks
This means that vector keeps memory allocated and have to do an in-place construction (=placement new) of objects being pushed into it. Is this a valid assumption?
Yes
Also, does this mean the container is manually invoking the destructor rather than calling delete?
Yes
Are there any other assumptions that I am missing here? Does this mean I can assume that even a custom written new for the object may not be invoked if I chose to write?
Yes. Consider that even in linked lists, the container will not allocate an instance of your type, but rather a templated structure that contains a subobject of the type. For a linked list that will be some complex type containing at least two pointers (both links) and a subobject of your type. The actual type that is allocated is that node, not your type.
Also it makes sense for a list to use a new and delete as we don't need the continuous memory guarantee.
It does, but it does not new
/delete
objects of your type.
So, is this kind of behavior is what drives how allocators behave?
I don't really understand this part of the question. Allocators are classes that have a set of constraints defined in the standard, that include both the interface (allocate
, deallocate
...) and semantics (the meaning of ==
is that memory allocated with one can be deallocated with the other, any other state in the class is irrelevant).
Allocators can be created and passed onto containers for different reasons, including efficiency (if you are only allocating a type of object, then you might be able to implement small block allocators slightly more efficient than malloc
--or not, depends on the situation).
Side note on placement new
I have always found interesting that placement new is a term that seems to have two separate meanings. On the one side is the only way of constructing an object in-place. But it seems to also have a complete different meaning: construct this object acquiring memory from a custom allocator.
In fact there is a single meaning of placement new that has nothing to do with constructing in-place. The first is just a case of the second, where the allocator is provided by the implementation (compiler) as defined in 18.4.1.3 and cannot be overloaded. That particular version of the overloaded allocator does absolutely nothing but return the argument (void*
) so that the new-expression can pass it into the constructor and construct the object on the memory (not) allocated by the placement new version that was called.
You're very close to being perfectly correct. The way that the vector
(and all the other standard containers) do their allocation is by using the std::allocator
class, which has support for constructing and destructing objects at particular locations. Internally, this uses placement new and explicit destructor calls to set up and destroy objects.
The reason I say "very close to being perfectly correct" is that it's possible to customize how STL containers get their memory by providing a new allocator as a template argument in lieu of the default. This means that in theory it should be possible to have STL containers construct and destruct objects in different ways, though by default they will use the standard placement new.