是否需要调用
reserve
取决于以下几个方面:
- 迭代器类型:对于输入迭代器,实现无法猜测其大小
- 库的质量:可能不会针对“更好”的迭代器进行专门优化
- 性能是否值得降低可维护性
让我们按顺序来看这三个方面。
1)迭代器类型
assign
方法接受至少符合
InputIterator
模型的两个迭代器。问题是,该模型表示纯源(例如来自网络的字节):您可以从中消耗两次。 因此,给定两个
InputIterator
,不可能在不提取数据的情况下计算它们之间的距离(除非您根本不想要数据,但这不是assign的目的),因此您不能先“reserve”。
这由
std::distance
至少需要
FowardIterator
来说明。
2)实现质量
我认为标准实际上没有规定“更好”的迭代器(至少模拟了
ForwardIterator
)的
assign
实现会使范围走两次。在受内存带宽限制的计算中(想象一下在磁带上读取该信息,倒回时间非常慢),这实际上会更加昂贵。
但是,许多实现(例如libc ++,请参见下文)会专门优化
assign
,以便在存在
ForwardIterator
的情况下首先调用
std::distance
来预留必要的内存。
注:同样适用于大规模插入。
3)维护负担
我要注意的是,尽管可能有所收益,但您(也许是无意中)在这里复制了信息。
size_t size = std::distance(begin, end);
if (begin != end) ++begin; // new line
v.reserve(size);
v.assign(begin, end);
看看新行的出现如何使代码略有不准确?并非不能工作,但所谓的优化不再那么正确: 现在你保留了太多!
个人而言,我会相信我的标准库实现会做正确的事情。撰写它们的人比我拥有更多的经验。
如果真的是应用程序中已知的瓶颈,你总可以按自己的方式尝试。只需编写一个 reserve_and_assign 方法来显示它的功能,并测量其是否更好。
供参考,这里是 libc++ 的实现,取自
这里:
template <class _Tp, class _Allocator>
template <class _InputIterator>
typename enable_if
<
__is_input_iterator <_InputIterator>::value &&
!__is_forward_iterator<_InputIterator>::value,
void
>::type
vector<_Tp, _Allocator>::assign(_InputIterator __first, _InputIterator __last)
{
clear();
for (; __first != __last; ++__first)
push_back(*__first);
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
typename enable_if
<
__is_forward_iterator<_ForwardIterator>::value,
void
>::type
vector<_Tp, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last)
{
typename iterator_traits<_ForwardIterator>::difference_type __new_size = _VSTD::distance(__first, __last);
if (static_cast<size_type>(__new_size) <= capacity())
{
_ForwardIterator __mid = __last;
bool __growing = false;
if (static_cast<size_type>(__new_size) > size())
{
__growing = true;
__mid = __first;
_VSTD::advance(__mid, size());
}
pointer __m = _VSTD::copy(__first, __mid, this->__begin_);
if (__growing)
__construct_at_end(__mid, __last);
else
this->__destruct_at_end(__m);
}
else
{
deallocate();
allocate(__recommend(static_cast<size_type>(__new_size)));
__construct_at_end(__first, __last);
}
}
std::distance
自动保留正确的内存。 - chris