Paul said:
And what if you need to add entries to this vector over time? Looking
at the *implementations* of a few STLs, it seems to me that for
efficiency reasons, they pretty much need to default constructor to be
there.
To add entries to your vector:
1. If doing so would require more space than is currently allocated,
allocate more space.
2. If the extra entries are being added anywhere but at the end of the
vector, you need to copy existing entries to new locations to make room
for the new entries, and to destroy existing entries to make room for
the objects that will be copied. I'm not familiar with the new "move
semantics" that are being considered for the next version of the C++
standard, but I presume that the existing entries might be moved rather
than copied and destroyed, where appropriate.
3. The new entries are then copied into the space reserved for them.
I don't see any need for the default constructor here. Certainly not for
efficiency's sake: adding calls to a default constructor at any place in
the above sequence would merely require corresponding calls to the
destructor, wasting time both ways.
The exception, of course, is if you want to insert new
default-constructed entries. That's precisely the point. None of the
standard containers requires that the contained type be default
constructible, unless you use those members which construct/insert
default-constructed elements into the container. That seems a very
reasonable way of handling it, and I don't see how mentioning that fact
qualifies as a criticism of the C++ standard containers.
This is one of the problems with RAII -- you cannot prepare
space for your objects asynchronously from their initialization, so
you are forced to initialize them twice; the first time being
knowingly irrelevant.
I don't what you're talking about. Every standard C++ container class
has an allocator class associated with it, either by explicitly using
std::vector<T,Allocator>, or by letting Allocator default to
std::allocator<T>.
Creating space for your objects asynchronously from their initialization
is precisely what the Allocator class is for. The Allocator::allocate()
function creates the space, without calling the constructor. The
Allocator::construct() function calls the appropriate constructor,
without having to allocate the space. The Allocator::destroy() function
calls the appropriate destructor, without deallocating the space. The
Allocator::deallocate() function releases the space, without calling the
destructor.
Calling std::vector::reserve() is the way for the end user to trigger a
call to Allocator::allocate(), if needed to reserve space for the
requested number of elements. One of the few criticisms I have of
std::vector is that calling reserve() with a value smaller than the
current value of capacity() is not guaranteed to make the appropriate
call to Allocator::deallocate().