Reducing the size of a std::vector without a default constructor
Your idea to use erase
is the right route. To reduce the amount of confusion, I would write a container based algorithm:
template<typename Container>
Container&& reduce_size( Container&& c, std::size_t amount ) {
amount = std::min( amount, c.size() ); // paranoid!
c.erase( end(c)-amount, end(c) );
return std::forward<Container>(c); // I like my container-algorithms to pass through
}
which will be as fast as your erase
implementation (well, one more branch and check).
Use:
std::vector< Foo > blah;
blah.emplace_back( 7 );
reduce_size( blah, 10 );
In my implementation, it looks like we have (with a few simplifications):
void std::vector<T,A>::resize(size_type __new_size)
{
if (__new_size > size())
_M_default_append(__new_size - size());
else if (__new_size < size())
_M_erase_at_end(begin() + __new_size);
}
auto std::vector<T,A>::erase(iterator __first, iterator __last) -> iterator
{
if (__first != __last)
{
if (__last != end())
_GLIBCXX_MOVE3(__last, end(), __first);
_M_erase_at_end(__first + (end() - __last));
}
return __first;
}
where _M_...
are private member functions. You really want the effects of _M_erase_at_end
. I would guess it would be hard or impossible for a compiler to optimize the _M_default_append
call out of v.resize(sz)
, but relatively easy to notice in v.erase(iter, v.end())
that __last == end()
and optimize away the _GLIBCXX_MOVE3
and the + (end() - __last)
. So erase()
could very well be more efficient than resize()
here.
I would expect most implementations to be a similar story: a few simple if
tests, and then calling some identical method to call destructors for elements at the end.