题
以下哪一个更好,为什么?(特别是对于c++)
A。
int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
//loop body
}
b.
for( int i(0);i < vec.length(); ++i)
{
//loop body
}
由于调用了 length 函数,我已经看到了对 (a) 的建议。这让我很烦恼。现代编译器没有对(b)进行与(a)类似的优化吗?
解决方案
实施例(b)中具有不同的含义与实施例(a)中,并且如你写编译器必须解释它。
如果,(对于我想不出一些虚构的原因),我写的代码来做到这一点:
for( int i(0);i < vec.length(); ++i)
{
if(i%4 == 0)
vec.push_back(Widget());
}
我真的不希望有编译器给每个呼叫优化出vec.length(),因为我会得到不同的结果。
其他提示
我喜欢:
for (int i = 0, e = vec.length(); i != e; ++i)
当然,这也将用于迭代器工作:
for (vector<int>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)
我喜欢这个,因为它是既有效(主叫end()
只是一次),并且还相对简洁(仅具有键入一次vector<int>::const_iterator
)。
我很惊讶,没有人说,很明显的:
<强>在箱子99.99%,它并不重要。强>
除非你使用的是一些容器,其中计算size()
是昂贵的操作,它是深不可测的,你的程序将走得几纳秒慢。我要说坚持使用更具可读性,直到你分析代码,发现size()
是一个瓶颈。
这里有两个问题需要争论:
- 变量范围
- 结束条件重新评估
变量范围
通常,您不需要循环变量在循环外部可见。这就是为什么你可以在里面声明它 for
构造。
结束条件重新评估
安德鲁·谢泼德(Andrew Shepherd)说得好:将函数调用放在结束条件中意味着不同的情况:
for( vector<...>::size_type i = 0; i < v.size(); ++i ) { // vector size may grow.
if( ... ) v.push_back( i ); // contrived, but possible
}
// note: this code may be replaced by a std::for_each construct, the previous can't.
for( vector<...>::size_type i = 0, elements = v.size(); i != elements; ++i ) {
}
为什么bodering吗? 这两个方案看不出是做的一样。一个正在做的迭代的固定数目,而另一种是依赖于环体
另一种替代方法是colud
for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
//loop body
}
除非需要外循环的循环变量,第二种方法是优选的。
迭代器实际上给你一样好或更好的性能。 (有上comp.lang.c大比较线程++。主持几年前)。
另外,我将使用
int i = 0;
而不是像语法构造你使用。虽然有效,它不是地道。
有点无关:
警告:符号和无符号整数的比较
<强>的正确类型阵列和矢量索引是为size_t 强>
严格来说,在C ++中它甚至std::vector<>::size_type
。
惊奇的是许多C / C ++开发者还是答错了这个问题。
让我们对生成的代码(我用2008 MSVS全部优化)看到的。
一个。
int i(0), iMax(vec.size());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
//loop body
}
for循环产生2个汇编指令。
湾
for( int i(0);i < vec.size(); ++i)
{
//loop body
}
for循环产生8个汇编指令。 vec.size()被成功地内联。
下进行。
for (std::vector<int>::const_iterator i = vec.begin(), e = vec.end(); i != e; ++i)
{
//loop body
}
for循环产生15个汇编指令(一切被内联,但代码有许多跳跃)
所以,如果您的应用程序性能的关键使用)。否则b)或c)。
应当注意的是,迭代的例子:
for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
//loop body
}
可能无效循环迭代“它”应该循环体导致矢量来重新分配。因此,它是不等同于
for (int i=0;i<vec.size();++i){
//loop body
}
其中循环体添加元素VEC。
简单问题:?你在环路修改vec
这个问题的答案会导致你的答案了。
JRH
这是非常难的编译器吊在安全知识vec.length()
调用,它是恒定的,除非它被内联(希望这往往会把!)。但至少i
一定要在第二风格“B”声明,即使length
调用需要“手动”吊出循环!
这个是更可取的:
typedef vector<int> container; // not really required,
// you could just use vector<int> in for loop
for (container::const_iterator i = v.begin(); i != v.end(); ++i)
{
// do something with (*i)
}
- 我可以马上告诉矢量没有更新
- 任何人都可以告诉这里发生了什么
- 我知道有多少个循环
v.end()
返回指针一个超过了最后一个元素,因此没有检查大小的开销- 易于更新不同的容器或价值类型
(B)将不计算/调用函数各一次。
- 开始摘录----
循环不变代码移动: GCC包括循环不变量代码运动作为其循环优化的一部分,以及在它的部分冗余消除通。这种优化从环路,其计算其不贯穿一个循环的寿命改变值删除的指令。
---端摘录 -
对于GCC更多优化:
https://www.in.redhat.com/software /gnupro/technical/gnupro_gcc.php3
#include <boost/foreach.hpp>
std::vector<double> vec;
//...
BOOST_FOREACH( double &d, vec)
{
std::cout << d;
}