使用迭代器获得向量的索引

时间:2020-03-06 14:42:42  来源:igfitidea点击:

在向量的元素上进行迭代时,最好使用迭代器而不是索引(请参阅为什么使用迭代器而不是数组索引?)。

std::vector<T> vec;
std::vector<T>::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
   // do work
}

但是,可能有必要在循环主体中使用索引。考虑到性能和灵活性/可扩展性,在那种情况下,以下哪一项更可取?

  • 恢复到索引循环
std::vector vec;
size_t i;
for ( i = 0; i < vec.size(); ++i )
{
   // use i
}
  • 计算偏移量
std::vector vec;
std::vector::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
   size_t i = it - vec.begin(); 
   // use i
}
  • 使用std :: distance
std::vector vec;
std::vector::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
   size_t i = std::distance( vec.begin(), it );
   // use i
}

解决方案

使用std :: distance更为通用,因为它适用于所有迭代器,而不仅仅是随机访问迭代器。在随机访问迭代器的情况下,它的速度应该与vec.begin()一样快。

vec.begin()基本上是指针算法。

还原到索引循环。

基本上在90%的情况下,迭代器是优越的,这是10%的情况之一。当使用迭代器的全部原因是简化代码时,通过使用迭代器会使代码更复杂,因此更难理解。

如果我们打算仅使用向量,则可能要切换回索引循环,因为它比迭代器循环更清楚地传达意图。但是,如果将来程序的发展可能会导致容器的更改,则应坚持使用迭代器,并使用std :: distance,这样可以保证与所有标准迭代器一起使用。

我们缺少一种解决方案:保留索引以防万一,但不要将其用作循环条件。同样适用于列表,并且成本(每个循环)为O(n)和一个额外的寄存器。

由于未来的发展原因,我总是倾向于与迭代器保持一致。

在上面的示例中,如果我们可能决定将std :: vector换成std :: set(也许我们需要一个唯一的元素集合),则使用迭代器和distance()将继续起作用。

我很确定所有性能问题都可以优化到可以忽略不计的程度。

假设std :: distance(vec.begin(),it)指向vec指向的索引。

卡尔

对于向量,我始终使用整数方法。向量的每个索引与数组查找的速度相同。如果我将大量使用该值,为方便起见,我创建了对此值的引用。

向量迭代器在理论上可能比索引稍快,因为它们使用指针算法来遍历列表。但是,通常我发现可读性值得最小的运行时差异。

我将迭代器用于其他容器类型,有时在不需要循环变量时使用。但是,如果我们需要循环变量,除了使循环更难键入之外,我们什么也不做。 (我不能等待c ++ 0x的自动运行。)