众所周知,在PHP中执行以下操作是个坏主意(因为每次迭代都会调用count ($array)
,这会严重降低脚本执行速度):
<?php
for ( $i = 0; $i < count ($array); ++$i )
{
// Code here;
}
相反,应该在循环之外计算条件:
<?php
$a = count ($array);
for ( $i = 0; $i < $a; ++$i )
{
// Code here;
}
我是编译语言的新手,所以我有一个问题:
例如,同样的规则适用于C和C ++等编译语言吗?
假设我想在C ++中迭代向量。我应该避免这样的循环还是没问题?
for ( int i = 0; i < vector.size(); ++i )
{
// Code here
}
如果这在编译语言中不是问题 - 是因为编译器会照顾它并优化可执行文件,或者还有其他原因吗?
答案 0 :(得分:2)
排序,for循环可以在C ++中解释如下:
{
int i = 0; // initializer
while(i < vector.size()){
// loop body
++i; // increment
}
}
所以size
被称为每个增量,它不是很重
由于您正在使用vector
,更好的方法是使用迭代器来保证安全:
for(auto iter = vector.begin(), end = vector.end(); iter != end; ++iter)
{
}
请注意,我在初始化时只初始化迭代器一次而不是与.end()
进行比较,这对于某些容器类型来说可能很昂贵,尽管vector
与调用{size
没什么不同。 1}}就效果而言。
或新的C ++ 11循环
for(auto & i: vector){
}
这实际上只是上面的迭代器示例的语法糖
老实说 C ++担心微观优化......应该避免使用可读性。与解释型语言不同,编译器可以做很多事情来解决小的性能错误。在微软的STL维护者的(转述)字眼“不要'帮助'编译器,你会让事情变得更糟”
答案 1 :(得分:1)
问题归结为“编译器是否在编译时知道答案”?
在你给出的情况下,答案是“不”。由于可以在循环中更改向量的大小,因此每次都应该对其进行评估(但它非常快,因为它一次不计算一个)。
这样的代码:
int myArray[20];
for(int ii = 0; ii < sizeof(myArray)/sizeof(*myArray); ii++) {
事实上,会在编译时评估sizeof
,因此会更有效率。注意 - 您需要整个表达式,因为在这种情况下sizeof(myArray)
本身将返回80
(其中int
是四个字节)。使用sizeof(*myArray)
的好处是,如果您改变对myArray
类型的看法,这行代码就不会中断...
你在这里使用除法的事实并没有减慢执行速度,因为它都是在编译期间完成的(只有一次)。
重新迭代我在评论中所说的内容:在这个例子中,你提出的版本,同时在每次迭代时评估向量的大小,实际上不是问题。除了最严格的循环外,你几乎不可能看到性能差异。不要落入the trap of micro-optimization
这是一个简单的计时示例:
#include <iostream>
#include <ctime>
#include <vector>
using namespace std;
int main(void) {
vector<int> testVector(200);
int ii, jj;
register int ss;
time_t startT, endT;
// case 1: using a constant for loop condition
startT = clock();
for(ii = 0; ii < 100000; ii++) {
for(jj = 0; jj < 200; jj++) {
testVector[jj] = ii - jj;
}
}
endT = clock();
printf("using constant: elapsed time: %.2f ms\n", (endT - startT) * 1000.0 / CLOCKS_PER_SEC);
// case 2: using size():
startT = clock();
for(ii = 0; ii < 100000; ii++) {
for(jj = 0; jj < testVector.size(); jj++) {
testVector[jj] = ii - jj;
}
}
endT = clock();
printf("using size: elapsed time: %.2f ms\n", (endT - startT) * 1000.0 / CLOCKS_PER_SEC);
// case 3: single call to size():
startT = clock();
ss = testVector.size();
for(ii = 0; ii < 100000; ii++) {
for(jj = 0; jj < ss; jj++) {
testVector[jj] = ii - jj;
}
}
endT = clock();
printf("with size out of loop: elapsed time: %.2f ms\n", (endT - startT) * 1000.0 / CLOCKS_PER_SEC);
}
这给出了以下结果:
using constant: elapsed time: 162.47 ms
using size: elapsed time: 277.02 ms
with size out of loop: elapsed time: 241.01 ms
正如您所看到的, 与在每个循环中查找向量大小相关的有限时间;但是对于20,000,000个呼叫大约需要100毫秒,或者每个呼叫大约需要5毫秒。这听起来是正确的;正如你所看到的,当你的循环足够紧密时,它是可测量的;但它在大多数“真正的”代码实例中都不太可能具有实际意义(在循环中你可能会做更多的事情)。正如您所看到的,只是将调用移动到size
的循环doest有很大帮助 - 使用常量vs变量是一个更大的区别。
答案 2 :(得分:1)
它是一样的。编译器或解释器无法知道整个循环中是否会改变大小。
但是,如果你知道你不会改变大小 - 你肯定可以在循环外计算变量,就像在PHP中一样。