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)
效率更高?还是相同?
答案 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)
所有优点:
没有任何问题(范围泄漏,预处理器魔术)。
我个人使用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.
}