获得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::iterator
和std::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::vector
variables – 这很清楚是什么意思,并且操作的简单性(它不过是一个指针减法)是用语法来表示的( distance
,在另一边听起来像一读毕达哥拉斯,不是吗?)。 正如UncleBen指出的那样-
在vector
被意外地改变为list
情况下,也充当静态断言。
另外我认为这是更普遍的 – 没有数字来certificate它,虽然。 主要论点: it - vec.begin()
在源代码中更短 – 更less的打字工作,更less的空间消耗。 很明显,你的问题的正确答案归结为一个品味的问题,这也可以是一个有效的论点。