以下哪项更好,为什么? (特别是c ++)
一个。
int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
//loop body
}
湾
for( int i(0);i < vec.length(); ++i)
{
//loop body
}
我已经看到了(a)的建议,因为调用了长度函数。这让我很烦。没有任何现代编译器将(b)的优化与(a)类似吗?
答案 0 :(得分:12)
示例(b)与示例(a)有不同的含义,编译器必须在编写时解释它。
如果,(由于某些我无法想到的原因),我编写了代码来执行此操作:
for( int i(0);i < vec.length(); ++i)
{
if(i%4 == 0)
vec.push_back(Widget());
}
我真的不希望编译器优化对vec.length()的每次调用,因为我会得到不同的结果。
答案 1 :(得分:10)
我喜欢:
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
一次)。
答案 2 :(得分:5)
我很惊讶没有人说明显的:
在99.99%的案例中,无所谓。
除非你使用某个容器来计算size()
是一项昂贵的操作,否则你的程序甚至会慢几纳秒,这是不可思议的。我会说在您分析代码并发现size()
是瓶颈之前,坚持使用更具可读性。
答案 3 :(得分:3)
这里有两个问题需要讨论:
通常,您不需要循环变量在循环外部可见。这就是为什么你可以在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 ) {
}
答案 4 :(得分:2)
为什么要和你一起玩? 这两种选择并没有看到做同样的事情。一个是进行固定数量的迭代,而另一个则依赖于循环体。
另一种选择是
for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
//loop body
}
答案 5 :(得分:2)
除非你需要在循环外部使用循环变量,否则第二种方法更可取。
迭代器实际上会给你带来更好或更好的性能。 (在comp.lang.c ++上有一个很大的比较线程。几年前就已经缓和了。)
另外,我会用
int i = 0;
而不是你正在使用的构造函数。虽然有效,但这不是惯用的。
答案 6 :(得分:2)
有些不相关:
警告:有符号和无符号整数之间的比较。
数组和矢量索引的正确类型是 size_t 。
严格说,在C ++中它甚至是std::vector<>::size_type
。
令人惊讶的是,有多少C / C ++开发人员仍然错了。
答案 7 :(得分:1)
让我们看一下生成的代码(我使用MSVS 2008进行全面优化)。
一个。
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个汇编指令(所有内容都是内联的,但代码有很多跳转)
因此,如果您的应用程序性能至关重要,请使用a)。否则b)或c)。
答案 8 :(得分:1)
应该注意迭代器的例子:
for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
//loop body
}
如果循环体导致向量重新分配,可能使循环迭代器'it'无效。因此它不等同于
for (int i=0;i<vec.size();++i){
//loop body
}
其中循环体将元素添加到vec。
答案 9 :(得分:0)
简单问题:你在循环中修改vec
吗?
JRH
答案 10 :(得分:0)
编译器很难在安全的情况下提升vec.length()
调用它是不变的,除非它被内联(希望它经常会!)。但至少i
应该在第二种样式“b”中声明,即使length
调用需要从循环中“手动”提升!
答案 11 :(得分:0)
这个更可取:
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()
返回指针
最后一个元素,所以没有开销
检查尺寸答案 12 :(得分:0)
(b)每次都不会计算/调用该函数。
- 开始摘录----
Loop Invariant Code Motion: GCC包括循环不变代码运动作为其循环优化器的一部分以及其部分冗余消除通道。此优化从循环中删除指令,循环计算的值在循环的整个生命周期内不会发生变化。
---结束摘录 -
gcc的更多优化:
https://www.in.redhat.com/software/gnupro/technical/gnupro_gcc.php3
答案 13 :(得分:0)
为什么不完全用BOOST_FOREACH
来回避这个问题#include <boost/foreach.hpp>
std::vector<double> vec;
//...
BOOST_FOREACH( double &d, vec)
{
std::cout << d;
}