以下哪一个更好,为什么?(特别是对于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()是一个瓶颈。

这里有两个问题需要争论:

  1. 变量范围
  2. 结束条件重新评估

变量范围

通常,您不需要循环变量在循环外部可见。这就是为什么你可以在里面声明它 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

scroll top