我正在尝试重复一段代码,不使用条件,但仍然只重复特定次数。
基本上是这样的:
repeat(50)
{
//Do stuff here.
}
有办法做到这一点吗?除了复制和粘贴50次?
我这样做是因为我想如果我知道有多少次我想重复一些事情,那么每次检查一个条件要快得多。那是准确的吗?或者我还会检查它重复了多少次?
基本上,它是否更快?
答案 0 :(得分:16)
您尝试通过使用某些构造(包括手动剪切和粘贴代码)来优化循环以优化循环的执行速度是不明智的。不要这样做;它可能会“取消优化”执行速度。
在我遇到过的任何C ++实现中(MSVC 6.0,2003,2005,2010,GCC各种版本,Diab各种版本),绝对没有,对不起我没有强调那么多,ZERO,时间涉及到分配循环计数变量,假设为分配循环计数变量的函数分配了任何其他变量。对于一个不进行函数调用的简单循环,循环计数变量甚至可能永远不会将其输出到内存中;它可以在整个生命周期内完全保存在单个CPU寄存器中。即使它存储在内存中,它也会在运行时堆栈上,并且它的空间(以及任何其他局部变量)将在一次操作中一次性声明,这不会花费更多或更少的时间,具体取决于堆栈上分配的变量。像循环计数器变量这样的局部变量在堆栈上分配,堆栈分配是CHEAP CHEAP CHEAP,而不是堆分配。
堆栈上的循环计数器变量分配示例:
for (int i=0; i<50; ++i) {
....
}
堆栈上的另一个循环计数器变量分配示例:
int i = 0;
for (; i<50; ++i) {
....
}
在堆上分配的示例循环计数器变量(不要这样做;它是愚蠢的):
int* ip = new int;
for (*ip=0; *ip<50; ++(*ip)) {
....
}
delete ip;
现在解决尝试通过手动复制&amp;来优化循环的问题。粘贴而不是使用循环和放大计数器:
您正在考虑的是循环展开的手动形式。循环展开是编译器有时用于减少循环中涉及的开销的优化。只有在编译时可以知道循环的迭代次数(即迭代次数是常数,即使常量涉及基于其他常量的计算),编译器也可以这样做。在某些情况下,编译器可能会确定展开循环是值得的,但通常它不会完全展开它。例如,在您的示例中,编译器可以确定将循环从50次迭代展开到仅循环体的5个副本的10次迭代将是速度优势。循环变量仍然存在,但是现在代码只需要进行10次比较,而不是对循环计数器进行50次比较。这是一个权衡,因为循环体的5个副本在缓存中占用了5倍的空间,这意味着加载相同指令的额外副本迫使缓存逐出(抛出)已经存在的许多指令缓存以及您可能希望保留在缓存中的缓存。此外,从主内存加载循环体指令的4个额外副本所花费的时间远远长于在未完全展开循环的情况下从缓存中抓取已经加载的指令。
总而言之,仅使用循环体的一个副本并继续将循环逻辑留在原位通常更有利。 (即,根本不进行任何循环展开。)
答案 1 :(得分:3)
完全可以将repeat(x)
作为语言的一部分,但由于某种原因没有这样的东西--C和C ++的设计确实有点跟随处理器可以做的事情,并且我不熟悉一个单处理器(我已经使用了大约10种不同的处理器架构),它可以进行“多次循环”,而无需“检查我们是否达到了这个数字”。
所以,你必须编写一些代码来检查你重复某些事情的次数(或者,还剩下多少次事情 - 有一个名为“loop”的x86指令就是这样 - 倒计时,如果计数器不为零,则跳转到循环的开头)。
如果编译器希望然后“展开”一个循环,因为它具有恒定的迭代次数,并且它决定“展开这个更快”[编译器一直决定这些东西,并且通常是正确的],然后编译器可能会这样做。但是你仍然需要编写“检查”的代码。
答案 2 :(得分:0)
如果您希望能够编写repeat(x) {}
的语法,可以使用宏。
类似的东西:
#include <iostream>
#define repeat(x) for(int i = x; i--;)
int main()
{
repeat(10)
{
std::cout << i << std::endl;
}
return 0;
}
此处的实现还使用for循环中的零而不是小于操作符may be slightly faster进行比较。
答案 3 :(得分:0)
如何?
Generator.GeneratePageLink
答案 4 :(得分:-1)
我不得不说,速度的最大提升是你没有分配迭代变量这一事实,但你要求的东西不可避免地要检查一个条件。实质上你所拥有的如下。
int i = 0;
for(; i< 50; i++)
{
Do Something.
}
我将我移到for循环之外的原因是声明它可以是循环之前初始化的任何变量。与...完全相同,
for(int i =0; i< 50; i++)
{
}