获得std :: vector迭代器索引的最有效方法是什么?

我遍历一个向量,并需要迭代器当前指向的索引。 AFAIK这可以通过两种方式完成:

  • it - vec.begin()
  • std::distance(vec.begin(), it)

这些方法的优缺点是什么?

我更喜欢it - vec.begin()恰恰是出于Naveen给出的相反原因:所以如果将向量更改为列表, 将无法编译。 如果在每次迭代过程中都这样做,那么最终可能会将O(n)algorithm变成O(n ^ 2)algorithm。

另一种select是,如果你在迭代过程中没有在容器中跳转,那么将索引作为第二个循环计数器。

我更喜欢std::distance(vec.begin(), it) ,因为它将允许我更改容器,而不需要任何代码更改。 例如,如果您决定使用std::list而不是std::vector ,它不提供随机访问迭代器,那么您的代码仍然可以编译。 由于std :: distance根据迭代器特征select最佳方法,所以不会有任何性能下降。

正如UncleBens和Naveen所表明的,两者都有很好的理由。 哪一个“更好”取决于你想要的行为:你想保证恒定时间的行为,还是希望在必要时回到线性时间?

it - vec.begin()需要一定的时间,但是operator -只是在随机访问迭代器上定义的,所以代码根本不会用列表迭代器编译。

std::distance(vec.begin(), it)适用于所有迭代器types,但是如果在随机访问迭代器上使用,则只会是一个常量操作。

两者都不是“更好”的。 使用你需要的那个。

我喜欢这一个: it - vec.begin() ,因为对我来说它清楚地说“距离开始”。 用迭代器我们习惯用算术来思考,所以符号是最明确的指标。

如果您已经将algorithm限制/硬编码为仅使用std::vector::iteratorstd::vector::iterator ,则最终使用哪种方法并不重要。 你的algorithm已经具体化,超越了select其中一个可以有所作为的地步。 他们都做同样的事情。 这只是一个个人喜好的问题。 我会亲自使用明确的减法。

另一方面,如果你想在algorithm中保留更高的通用性,也就是说,为了让将来有一天它可能被应用到其他迭代器types中,那么最好的方法取决于你的意图。 这取决于你想在这里可以使用的迭代器types的限制。

  • 如果使用显式减法,则algorithm将被限制为一个相当狭窄的迭代器类:随机访问迭代器。 (这是你从std::vector

  • 如果你使用distance ,你的algorithm将支持更广泛的迭代器类:input迭代器。

当然,计算非随机访问迭代器的距离通常是一个低效率的操作(同样,对于随机访问迭代器,它的效率与减法效率一样)。 效率方面,决定你的algorithm对于非随机访问迭代器是否有意义取决于你。 由此产生的效率损失对于使你的algorithm完全无用而言是毁灭性的,那么你应该更好地坚持减法,从而禁止低效率的使用,迫使用户为其他迭代types寻求替代解决scheme。 如果非随机访问迭代器的效率仍然在可用范围内,则应该使用distance并logging随机访问迭代器可以更好地工作的事实。

根据http://www.cplusplus.com/reference/std/iterator/distance/ ,由于vec.begin()是一个随机访问迭代器,距离方法使用-运算符。

所以从性能的angular度来看,答案是一样的,但是如果有人需要阅读和理解你的代码,使用distance()会更容易理解。

我只会使用std::vectorvariables – 这很清楚是什么意思,并且操作的简单性(它不过是一个指针减法)是用语法来表示的( distance ,在另一边听起来像一读毕达哥拉斯,不是吗?)。 正如UncleBen指出的那样-vector被意外地改变为list情况下,也充当静态断言。

另外我认为这是更普遍的 – 没有数字来certificate它,虽然。 主要论点: it - vec.begin()在源代码中更短 – 更less的打字工作,更less的空间消耗。 很明显,你的问题的正确答案归结为一个品味的问题,这可以是一个有效的论点。