As a followup to this question, the default allocator (std::allocator<T>
) is required to implement construct
as follows (according to [default.allocator]):
template <class U, class... Args> void construct(U* p, Args&&... args);
Effects:
::new((void *)p) U(std::forward<Args>(args)...)
That is, always value-initialization. The result of this is that std::vector<POD> v(num)
, for any pod type, will value-initialize num
elements - which is more expensive than default-initializing num
elements.
Why didn't† std::allocator
provide a default-initializing additional overload? That is, something like (borrowed from Casey):
template <class U>
void construct(U* p) noexcept(std::is_nothrow_default_constructible<U>::value)
{
::new(static_cast<void*>(p)) U;
}
Was there a reason to prefer value initialization in call cases? It seems surprising to me that this breaks the usual C++ rules where we only pay for what we want to use.
†I assume such a change is impossible going forward, given that currently std::vector<int> v(100)
will give you 100 0
s, but I'm wondering why that is the case... given that one could just as easily have required std::vector<int> v2(100, 0)
in the same way that there are differences between new int[100]
and new int[100]{}
.
In C++03 Allocators
construct
member took two arguments: pointer and value which was used to perform copy-initialization:construct
taking two parameters can be traced back to 1994 (pg. 18). As you can see, in orignal Stepanov concepts it wasn't part of allocator interface (it wasn't supposed to be configurable) and was present just as wrapper over placement new.Only way to know for sure would to ask Stepanov himself, but I suppose that reason was following: if you want to construct something, you want to initialize it with specific value. And if you want your integers uninitializated, you can just omit
construct
call since it is not needed for POD types. Laterconstruct
and other related function were bundled into allocators and containers were parametrized on them introducing some loss of control on initialization for end user.So it seems that lack of default initialization is for historical reasons: nobody though about its importance when C++ was standardized and later versions of the Standard would not introduce breaking change.