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.

Tags:

C++

Stl