Question
Which of 2 implementation is more close to the specification?
#1
template <typename Iter>
vector::vector(Iter first, Iter last)
{
reserve(std::distance(first, last));
for (auto it = first; it != last; it++)
{ push_back(*it); }
}
#2
template <typename Iter>
vector::vector(Iter first, Iter last)
{
for (auto it = first; it != last; it++)
{ push_back(*it); }
}
The reserving implementation (#1) runs two times through the range if Iter
is a not random access iterator. The first time is in std::distance
to determine vector size, the second time is in the constructor itself for filling the vector with elements.
The reserve-less implementation (#2) is always single-pass. But if the vector is out of capacity, then reallocations happen which involve additional "pass through the range" actions. So in generate the #1 implementation has better performance.
Therefore I'm almost sure that the correct answer is #1. Also GNU C++ standard library does it this way. But I'm still curious.
The question may be more relevant to corresponding assign
method that takes range as a parameter, because, when doing assign, the vector may have enough capacity, and so doing reserve
before assign
is redundant. Therefore it is unclear if vector assign reserves required capacity before filling.
Answer
Yes, it's guaranteed that there will be no reallocations, because pointers are RandomAccessIterators. vector.cons/9
template <class InputIterator> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
Effects: Constructs a vector equal to the range
[first, last)
, using the specified allocator.Complexity: Makes only
N
calls to the copy constructor ofT
(whereN
is the distance betweenfirst
andlast
) and no reallocations if iterators first and last are of forward, bidirectional, or random access categories. It makes orderN
calls to the copy constructor ofT
and orderlog(N)
reallocations if they are just input iterators.