6
vector<int> a;

1.

for(vector<int>::iterator it = a.begin(); it != a.end(); ++it)

2.

vector<int>::iterator end = a.end();
for(vector<int>::iterator it = a.begin(); it != end; ++it)

哪个更高效?还是一样?

4

4 回答 4

10

初步批评:

1/典型教程示例

for(vector<int>::iterator it = a.begin(); it != a.end(); ++it)

没有魔法,但它提出了一个问题:a循环中是否曾经修改过最终界限可能会有所不同?

2/改进

vector<int>::iterator end = a.end();
for(vector<int>::iterator it = a.begin(); it != end; ++it)

a.end()似乎只执行一次。但是,由于endis not const,因此可以在循环内对其进行修改。

此外,它end在外部范围中引入了标识符,污染了它。

因此,性能有潜在的提升,但清晰度并不高。此外,它更加冗长。


我会提出其他几种方法:

3/最佳手册

for(vector<int>::iterator it = a.begin(), end = a.end(); it != end; ++it)

结合了v1(非常简洁,没有外部范围污染)和v2(性能)的优点,但是目前还不清楚是否end曾经在循环体内修改过。

4/升压供电

BOOST_FOREACH(int& i, a)

甚至更简洁v1,一目了然,没有外部范围泄漏,并保证完全迭代(不可能修改边界)。

很遗憾:

  • 变量类型中的逗号存在问题(因为它依赖于预处理器)
  • 编译时错误是完全神秘的(因为它依赖于预处理器)

注意:理论上,可以在std::foreach这里提出算法的案例,但老实说......在外部定义谓词需要付出太多努力,并且会破坏代码局部性。

5/ C++11 range-for 语句

for (int& i: a)

所有优点:

  • 非常简洁
  • 与最佳 C++ 手写循环一样高效
  • 保证完整迭代,不问任何问题

并且没有任何问题(范围泄漏,预处理器魔术)。


就个人而言,我尽可能使用 C++11 range-for(业余爱好项目)和BOOST_FOREACH其他情况(在工作中)。

我避免像瘟疫一样修改我正在迭代的容器,当我需要过滤/删除元素时更喜欢依赖 STL 算法......否则很容易弄乱边界条件和迭代器失效。

于 2012-04-27T07:49:06.393 回答
6

2nd 更有效,因为它只需要创建一次结束迭代器。

智能编译器可能会将第一个优化为第二个,但您不能保证会发生这种情况。

这实际上是一个复杂的优化,因为编译器需要 100% 确定对 end() 的任何后续调用都不会产生额外的影响或返回任何不同的东西。基本上,它需要知道至少在循环中,end() 总是返回一些这样的东西,即 end() == 之前对 end() 的调用。不能保证编译器是否进行优化。

于 2012-04-27T07:12:29.573 回答
1

第二种方式显然更好,因为它只调用a.end()一次。本质上,如果您的树中有N个节点,那么您将N次调用保存到a.end()

于 2012-04-27T07:15:50.683 回答
0

我认为第一个 for 循环更确定。如果您在此 for 循环中插入/删除元素,end您定义的迭代器将失效。例如:

vector<int>::iterator mend = int_vec.end(), mbegin = int_vec.begin();
while(mbegin != mend)
{
    cout << *mbegin << " ";
    int_vec.erase(mbegin);
    // mbegin is automatically invalidated
    // execution of this program causes bizarre runtime_error !
    // never try this at home !
}

上述代码的更安全版本可能是:

vector<int>::iterator mend = int_vec.end(), mbegin = int_vec.begin();
while(mbegin != mend)
{
    cout << *mbegin << " ";
    int_vec.erase(mbegin);
    mbegin = int_vec.begin(); // ok, mbegin updated.
}
于 2012-05-04T15:25:11.637 回答