C ++中的表单有两个不同之处吗?

时间:2012-04-27 07:11:04

标签: c++

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 个答案:

答案 0 :(得分: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()只执行一次。但是,由于end不是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 statement

for (int& i: a)

所有优点:

  • 极端Terse
  • 与最佳C ++手写循环一样高效。
  • 保证完整的迭代,没有问题

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


我个人使用C ++ 11范围 - 我可以随时(爱好项目)和BOOST_FOREACH(在工作中)。

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

答案 1 :(得分:6)

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

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

这实际上是一个复杂的优化,因为编译器需要100%确定对end()的任何后续调用都没有其他影响或返回任何不同的东西。基本上,它需要知道至少在循环中,end()总是返回一些东西,例如end()==以前调用end()。编译器是否进行了优化并不能保证。

答案 2 :(得分:1)

第二种方式显然更好,因为它只召唤一次 a.end()。实质上,如果树中有 N 节点,则将 N 调用保存到 a.end()

答案 3 :(得分: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.
}