迭代容器的最佳方法

时间:2021-02-01 01:50:11

What are the Advantages/Drawbacks of these two ways of iterating through a container / which one do you prefer and why:

这两种迭代容器的方法有哪些优点/缺点/您喜欢哪种方式以及原因:

for (MyClass::iterator i = m.begin(), e = m.end() ; i != e ; i++)
{
    // ...
}

or

for (MyClass::iterator i = m.begin() ; i != m.end() ; i++)
{
    // ...
}

Subsidiary question: i++ or ++i? Why?

附属问题:i ++或++ i?为什么?

7 个解决方案

#1


If the iterator is non-trivial (ie. not a pointer), ++i is definitely faster as it doesn't involves a copy to a temporary, which may or may not be optimized out.

如果迭代器是非平凡的(即不是指针),++ i肯定更快,因为它不涉及复制到临时,可能会也可能不会被优化。

The first form is a little faster but could be wrong if you erase or insert things in the loop.

第一种形式更快一点,但如果你在循环中删除或插入东西可能是错误的。

For simple iteration over a container I use

对于我使用的容器的简单迭代

#define foreach BOOST_FOREACH // in some header

foreach(MyType &element, any_container) {
  // deal with element
}

most of the time for succinctness and clarity.

大部分时间都是简洁明了。

#2


Unless you have optimizations turned off, both are equivalent. As for i++ or ++i, ++i is more efficient because it does not involve a temporary value.

除非你关闭了优化,否则两者都是等价的。对于i ++或++ i,++ i更有效,因为它不涉及临时值。

#3


For normal stl iterators there's not a great deal of difference however if you collections are complex and asking for end is expensive then only asking for the end once may be faster.

对于普通的stl迭代器,没有太大的区别,但是如果你的集合很复杂并且要求结束是昂贵的,那么只要求结束一次可能会更快。

Similarly for ++i vs i++, ++i can be a more expensive operation when the iterator is a complex class (rather than just a pointer as in the stl iterators) with i++ what's happening is that it's incrementing the iterator but returning a copy of the iterator in it's previous state. for ++i it's returning the iterator in it's current state so can just return a reference to itself.

类似地,对于++ i vs i ++,++当迭代器是一个复杂的类(而不仅仅是stl迭代器中的指针)时,我可能是一个更昂贵的操作,而i ++正在发生的事情是它正在递增迭代器但是返回一个副本迭代器在它之前的状态。 for ++ i它返回迭代器的当前状态,所以只能返回对它自己的引用。

It's usually best to only optimize your code when your profiler identifies that there's a problem there - it's better to keep the code as easily readable as possible.

通常最好只在分析器识别出存在问题时优化代码 - 最好使代码尽可能易读。

#4


I always do the second one actually, although I do worry sometimes if multiple calls to end slows things down at all. I was under the impression this would be optimised, but don't know that for sure.

我总是会做第二个,虽然我有时会担心如果多次调用结束会让事情变慢。我认为这会被优化,但不确定。

And ++i definitely. It's never slower than i++, if anything it's faster.

而且我绝对是。它永远不会慢于i ++,如果它更快的话。

#5


The first one is faster because end() isn't called on every iteration. And no, the optimizer can't easily cache that for you, because it doesn't know whether the size of the container has changed in this iteration (and hence the end moved). This also applies to a const container due to the aliasing problem.

第一个更快,因为每次迭代都不会调用end()。不,优化器不能轻易地为您缓存,因为它不知道容器的大小在此迭代中是否已更改(因此结束移动)。由于别名问题,这也适用于const容器。

i++ returns a copy of i, then increments. ++i increments, then returns the incremented value. Hence, when you are discarding the return value, use ++i because it needs to do less work (no copying). The optimizer is quite likely to fix an inlined i++ call so it's as fast as ++i but don't rely on that.

i ++返回i的副本,然后递增。 ++ i递增,然后返回递增的值。因此,当您丢弃返回值时,请使用++ i,因为它需要做更少的工作(不复制)。优化器很可能修复内联的i ++调用,因此它与++ i一样快,但不依赖于它。

Me? I use

我?我用

for(int i = 0; i < m.size(); i++) {
    // ... do something with m[i]
}

Because it's the shortest and most clear. Why int and not MyClass::size_type? Because it's simpler and I have never had to worry about the edge cases so far. Why i++? Because for basic types it's always optimized into ++i, and it's less confusing for coworkers. As a bonus, I can use i as a numeric value as well. With an iterator, I'd have to keep a separate counter, or use std::distance.

因为它是最短且最清晰的。为什么是int而不是MyClass :: size_type?因为它更简单,我从来没有担心边缘情况到目前为止。为什么选择i ++?因为对于基本类型,它总是被优化为++ i,并且对同事来说不那么容易混淆。作为奖励,我也可以使用i作为数值。使用迭代器,我必须保留一个单独的计数器,或使用std :: distance。

obecalp points out that this doesn't work with half of the standard containers, like list and map. Indeed those require using a proper iterator. Relatedly, you should always use an iterator when writing generic code.

obecalp指出,这不适用于一半的标准容器,如list和map。实际上,那些需要使用适当的迭代器。相关地,在编写通用代码时应始终使用迭代器。

#6


Boost.Foreach introduces a nice way:

Boost.Foreach介绍了一个很好的方法:

#define foreach         BOOST_FOREACH
// ...
Container<Item> container;
// ...
foreach (Item item, container) {
  // do some stuff with the item
}

#7


The C++ "for every element in container" loop is the most efficient where the context doesn't call for iterative logic.

C ++“for container中的每个元素”循环是上下文不调用迭代逻辑的最有效的。

for(Item i : Container)
{
     dosomething(i);
}

#1


If the iterator is non-trivial (ie. not a pointer), ++i is definitely faster as it doesn't involves a copy to a temporary, which may or may not be optimized out.

如果迭代器是非平凡的(即不是指针),++ i肯定更快,因为它不涉及复制到临时,可能会也可能不会被优化。

The first form is a little faster but could be wrong if you erase or insert things in the loop.

第一种形式更快一点,但如果你在循环中删除或插入东西可能是错误的。

For simple iteration over a container I use

对于我使用的容器的简单迭代

#define foreach BOOST_FOREACH // in some header

foreach(MyType &element, any_container) {
  // deal with element
}

most of the time for succinctness and clarity.

大部分时间都是简洁明了。

#2


Unless you have optimizations turned off, both are equivalent. As for i++ or ++i, ++i is more efficient because it does not involve a temporary value.

除非你关闭了优化,否则两者都是等价的。对于i ++或++ i,++ i更有效,因为它不涉及临时值。

#3


For normal stl iterators there's not a great deal of difference however if you collections are complex and asking for end is expensive then only asking for the end once may be faster.

对于普通的stl迭代器,没有太大的区别,但是如果你的集合很复杂并且要求结束是昂贵的,那么只要求结束一次可能会更快。

Similarly for ++i vs i++, ++i can be a more expensive operation when the iterator is a complex class (rather than just a pointer as in the stl iterators) with i++ what's happening is that it's incrementing the iterator but returning a copy of the iterator in it's previous state. for ++i it's returning the iterator in it's current state so can just return a reference to itself.

类似地,对于++ i vs i ++,++当迭代器是一个复杂的类(而不仅仅是stl迭代器中的指针)时,我可能是一个更昂贵的操作,而i ++正在发生的事情是它正在递增迭代器但是返回一个副本迭代器在它之前的状态。 for ++ i它返回迭代器的当前状态,所以只能返回对它自己的引用。

It's usually best to only optimize your code when your profiler identifies that there's a problem there - it's better to keep the code as easily readable as possible.

通常最好只在分析器识别出存在问题时优化代码 - 最好使代码尽可能易读。

#4


I always do the second one actually, although I do worry sometimes if multiple calls to end slows things down at all. I was under the impression this would be optimised, but don't know that for sure.

我总是会做第二个,虽然我有时会担心如果多次调用结束会让事情变慢。我认为这会被优化,但不确定。

And ++i definitely. It's never slower than i++, if anything it's faster.

而且我绝对是。它永远不会慢于i ++,如果它更快的话。

#5


The first one is faster because end() isn't called on every iteration. And no, the optimizer can't easily cache that for you, because it doesn't know whether the size of the container has changed in this iteration (and hence the end moved). This also applies to a const container due to the aliasing problem.

第一个更快,因为每次迭代都不会调用end()。不,优化器不能轻易地为您缓存,因为它不知道容器的大小在此迭代中是否已更改(因此结束移动)。由于别名问题,这也适用于const容器。

i++ returns a copy of i, then increments. ++i increments, then returns the incremented value. Hence, when you are discarding the return value, use ++i because it needs to do less work (no copying). The optimizer is quite likely to fix an inlined i++ call so it's as fast as ++i but don't rely on that.

i ++返回i的副本,然后递增。 ++ i递增,然后返回递增的值。因此,当您丢弃返回值时,请使用++ i,因为它需要做更少的工作(不复制)。优化器很可能修复内联的i ++调用,因此它与++ i一样快,但不依赖于它。

Me? I use

我?我用

for(int i = 0; i < m.size(); i++) {
    // ... do something with m[i]
}

Because it's the shortest and most clear. Why int and not MyClass::size_type? Because it's simpler and I have never had to worry about the edge cases so far. Why i++? Because for basic types it's always optimized into ++i, and it's less confusing for coworkers. As a bonus, I can use i as a numeric value as well. With an iterator, I'd have to keep a separate counter, or use std::distance.

因为它是最短且最清晰的。为什么是int而不是MyClass :: size_type?因为它更简单,我从来没有担心边缘情况到目前为止。为什么选择i ++?因为对于基本类型,它总是被优化为++ i,并且对同事来说不那么容易混淆。作为奖励,我也可以使用i作为数值。使用迭代器,我必须保留一个单独的计数器,或使用std :: distance。

obecalp points out that this doesn't work with half of the standard containers, like list and map. Indeed those require using a proper iterator. Relatedly, you should always use an iterator when writing generic code.

obecalp指出,这不适用于一半的标准容器,如list和map。实际上,那些需要使用适当的迭代器。相关地,在编写通用代码时应始终使用迭代器。

#6


Boost.Foreach introduces a nice way:

Boost.Foreach介绍了一个很好的方法:

#define foreach         BOOST_FOREACH
// ...
Container<Item> container;
// ...
foreach (Item item, container) {
  // do some stuff with the item
}

#7


The C++ "for every element in container" loop is the most efficient where the context doesn't call for iterative logic.

C ++“for container中的每个元素”循环是上下文不调用迭代逻辑的最有效的。

for(Item i : Container)
{
     dosomething(i);
}