I have a templated class using a std::vector
of it's template argument. The argument may not be default constructible. I want to reduce the size of the vector (cut it to a given size). Obviously
vec.resize( reduced_size );
...doesn't work as it requires a default constructor.
I could of course:
While writing the question, I noticed that I can erase
the elements from the vector up to the end:
vec.erase ( vec.begin() + position, vec.end() );
... however, I'm not sure if this will be as efficient as resize
.
Is there an efficient way to reduce a vector's size without a default constructor?
C++11 solutions are acceptable.
EDIT: Seems that both MSVC and GCC implement shrinking resize as a erase call, so that answers my performance question.
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.
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 );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With