在整个网络上,代码示例都有for
个循环,如下所示:
for(int i = 0; i < 5; i++)
虽然我使用以下格式:
for(int i = 0; i != 5; ++i)
我这样做是因为我认为它更有效率,但这在大多数情况下是否真的重要?
答案 0 :(得分:86)
每个人都喜欢他们的微观优化,但就我所见,这并没有什么不同。我使用g ++编译了两个变体,用于英特尔处理器,没有任何花哨的优化,结果是
for(int i = 0; i < 5; i++)
movl $0, -12(%ebp)
jmp L2
L3:
leal -12(%ebp), %eax
incl (%eax)
L2:
cmpl $4, -12(%ebp)
jle L3
for(int i = 0; i != 5; ++i)
movl $0, -12(%ebp)
jmp L7
L8:
leal -12(%ebp), %eax
incl (%eax)
L7:
cmpl $5, -12(%ebp)
jne L8
我认为jle
和jne
应该转化为大多数架构上同样快速的指令。
所以对于性能,你不应该区分这两者。总的来说,我同意第一个更安全,我也认为更常见。
编辑(2年后):由于这个帖子最近再次得到了很多关注,我想补充说,一般来说很难回答这个问题。 C-Standard [PDF]特别没有定义哪些版本的代码更高效(同样适用于C ++,也可能适用于C#)。
第5.1.2.3节程序执行
§1本国际标准中的语义描述描述了抽象机器的行为,其中优化问题无关紧要。
但是可以合理地假设现代编译器会生成同样高效的代码,我认为只有极少数情况下 loop-test 和计算表达式是for循环的瓶颈。
至于味道,我写
for(int i = 0; i < 5; ++i)
答案 1 :(得分:69)
如果由于某种原因i
在循环中跳转到50,那么你的版本将永远循环。 i < 5
是一个完整性检查。
答案 2 :(得分:41)
表格
for (int i = 0; i < 5; i++)
是惯用的,因此对于有经验的C程序员来说,它更容易阅读。 特别是当用于迭代数组时。 你应该尽可能地编写惯用代码,因为它读得更快。
在循环中修改i或使用不同于1的增量时,它也会更安全一些。 但这是一件小事。 最好仔细设计你的循环并添加一些断言来尽早捕捉破坏的假设。
答案 3 :(得分:18)
如果增量规则略有变化,则会立即产生无限循环。我更喜欢第一个结束条件。
答案 4 :(得分:13)
这取决于语言。
C ++文本经常建议第二种格式,因为它可以与迭代器一起使用,可以直接比较(!=),但不能与更大或更小的条件进行比较。预增量也可以比后增量快,因为不需要变量的副本进行比较 - 但是优化者可以处理这个。
对于整数,要么形成作品。 C的常见习语是第一个,而对于C ++,它是第二个。
对于C#和Java的使用,我会尽力遍历所有事情。
在C ++中还有std :: for_each函数需要使用一个仿函数,对于简单的情况,它可能比这里的示例和Boost FOR_EACH更复杂,它们看起来像C#foreach但内部很复杂。
答案 5 :(得分:12)
关于使用++ i而不是i ++,它与大多数编译器没有区别,但是当用作迭代器时,++我可能比i ++更有效。
答案 6 :(得分:10)
实际上,你提供的内容有四种排列方式。对你们两个:
for(int i = 0; i < 5; i++)
for(int i = 0; i != 5; ++i)
我们可以添加:
for(int i = 0; i < 5; ++i)
for(int i = 0; i != 5; i++)
在大多数具有现代编译器的现代机器上,这些效率完全相同并不奇怪。你可能有一天可能会发现自己正在为一些小型处理器编程,而平等比较和低于比较之间存在差异。
在某些情况下,根据我们选择0和5的原因,某个特定情况的特定情况可能会更有意义地考虑“小于”或“不等于”,但即便如此对一个程序员来说显而易见的可能不是另一个。
更抽象地说,这些是以下形式:
for(someType i = start; i < end; i++)
for(someType i = start; i != end; ++i)
for(someType i = start; i < end; ++i)
for(someType i = start; i != end; i++)
这里明显不同的是,在两种情况下,someType
必须具有<
的含义,其余!=
必须具有含义!=
。定义<
和!=
的类型并不常见,包括C ++中的很多迭代器对象(可能在C#中,与STL迭代器相同的方法是可能的,有时也很有用,但是既不是惯用的,也不是由公共图书馆直接支持,也不是经常有用,因为有竞争对手的习语有更直接的支持)。值得注意的是,STL方法是专门设计的,以便在有效迭代器类型集中包含指针。如果您习惯使用STL,即使应用于整数,您也会认为具有<
的表单更具惯用性。就个人而言,接触它的次数足以让我的本能。
另一方面,虽然定义!=
而不是i
会更少见,但它适用于我们用i
的值增加替换增量的情况,或者在循环中可以改变++i
的地方。
因此,双方都有明确的案例,其中一种是唯一的方法。
现在为i++
vs ++
。再次使用整数并且直接调用而不是通过返回结果的函数(并且偶然的机会),实际结果将完全相同。
在某些C风格的语言中(没有运算符过载的语言)整数和指针是唯一的情况。我们可以人为地发明一个案例,通过函数调用增量来改变它的运行方式,编译器仍然可能会将它们变成同样的东西。
C ++和C#允许我们覆盖它们。通常,前缀val = OneMoreThan(val);//whatever OneMoreThan means in the context.
//note that we assigned something back to val here.
return val;
的作用类似于:
++
后缀SomeType copy = Clone(val);
val = OneMoreThan(val);
return copy;
的运作方式类似于:
this
C ++和C#都不能完美地匹配上述内容(我故意不使我的伪代码匹配),但在任何一种情况下都可能有副本或者两个副本。这可能贵也可能不贵。它可能是可避免的,也可能是不可避免的(在C ++中,我们通常可以通过返回++i
完全避免它的前缀形式,并通过返回void来避免它在后缀中。它可能会也可能不会被优化为任何东西,但在某些情况下,i++
比++i
更有效率。
更具体地说,使用{{1}}可能会略微提升性能,并且使用大型类甚至可能相当大,但禁止有人在C ++中重写,以便两者具有完全不同的含义(非常漂亮)坏主意)这通常不可能是另一种方式。因此,养成在postfix上使用前缀的习惯意味着你可能会在千分之一中获得一次改进,但不会失败,所以这是C ++程序员经常进入的习惯。
总之,在您的问题中给出的两种情况绝对没有区别,但可以有相同的变体。
答案 7 :(得分:9)
在阅读了Dijkstra的一本名为"A Discipline of Programming"的书之后,我在大约20多年前转而使用!=
。在他的书中,Dijkstra观察到较弱的延续条件导致循环结构中更强的后置条件。
例如,如果我们修改你的构造以在循环之后公开i
,那么第一个循环的后置条件将是i >= 5
,而第二个循环的后置条件是很多更强i == 5
。这对于循环不变量,后置条件和最弱条件的正式条件下的程序推理更好。
答案 8 :(得分:6)
我同意关于可读性的说法 - 重要的是让代码对于维护者来说很容易阅读,尽管你希望那些人能够理解前后增量。
那就是说,我认为我会进行一个简单的测试,并得到一些关于四个循环中哪个循环运行最快的可靠数据。 我使用的是平均规格的计算机,使用javac 1.7.0进行编译。
我的程序进行了一个for循环,在没有任何东西的情况下迭代了2,000,000次(以免淹没有趣的数据以及在for循环中执行任何操作所花费的时间)。它使用上面提出的所有四种类型,并对结果进行计时,重复1000次以获得平均值。
实际代码是:
public class EfficiencyTest
{
public static int iterations = 1000;
public static long postIncLessThan() {
long startTime = 0;
long endTime = 0;
startTime = System.nanoTime();
for (int i=0; i < 2000000; i++) {}
endTime = System.nanoTime();
return endTime - startTime;
}
public static long postIncNotEqual() {
long startTime = 0;
long endTime = 0;
startTime = System.nanoTime();
for (int i=0; i != 2000000; i++) {}
endTime = System.nanoTime();
return endTime - startTime;
}
public static long preIncLessThan() {
long startTime = 0;
long endTime = 0;
startTime = System.nanoTime();
for (int i=0; i < 2000000; ++i) {}
endTime = System.nanoTime();
return endTime - startTime;
}
public static long preIncNotEqual() {
long startTime = 0;
long endTime = 0;
startTime = System.nanoTime();
for (int i=0; i != 2000000; ++i) {}
endTime = System.nanoTime();
return endTime - startTime;
}
public static void analyseResults(long[] data) {
long max = 0;
long min = Long.MAX_VALUE;
long total = 0;
for (int i=0; i<iterations; i++) {
max = (max > data[i]) ? max : data[i];
min = (data[i] > min) ? min : data[i];
total += data[i];
}
long average = total/iterations;
System.out.print("max: " + (max) + "ns, min: " + (min) + "ns");
System.out.println("\tAverage: " + (average) + "ns");
}
public static void main(String[] args) {
long[] postIncLessThanResults = new long [iterations];
long[] postIncNotEqualResults = new long [iterations];
long[] preIncLessThanResults = new long [iterations];
long[] preIncNotEqualResults = new long [iterations];
for (int i=0; i<iterations; i++) {
postIncLessThanResults[i] = postIncLessThan();
postIncNotEqualResults[i] = postIncNotEqual();
preIncLessThanResults[i] = preIncLessThan();
preIncNotEqualResults[i] = preIncNotEqual();
}
System.out.println("Post increment, less than test");
analyseResults(postIncLessThanResults);
System.out.println("Post increment, inequality test");
analyseResults(postIncNotEqualResults);
System.out.println("Pre increment, less than test");
analyseResults(preIncLessThanResults);
System.out.println("Pre increment, inequality test");
analyseResults(preIncNotEqualResults);
}
}
很抱歉,如果我错误地复制了它!
结果让我觉得 - 测试i < maxValue
每个循环大约需要1.39ms,无论是使用前增量还是后增量,但是i != maxValue
需要1.05ms。这可能是24.5%的节省或32.5%的时间损失,具体取决于你如何看待它。
当然,运行for循环所需的时间可能不是你的瓶颈,但这是一种有用的优化,对于你需要它的罕见场合。
我认为我仍然坚持不到测试!
修改强>
我已经测试了减少i,并发现这并没有真正产生影响 - for (int i = 2000000; i != 0; i--)
和for (int i = 0; i != 2000000; i++)
都花费相同的时间长度,就像for (int i = 2000000; i > 0; i--)
和for (int i = 0; i < 2000000; i++)
。
答案 9 :(得分:4)
在通用代码中,您应该更喜欢使用!=
运算符的版本,因为它只需要i
具有可比性,而<
版本需要它是关系可比的。后者比前者更强烈。当一个较弱的要求完全足够时,你通常应该更愿意避免更强烈的要求。
话虽如此,在您的具体情况下,如果int i
两者同样有效并且性能不会有任何差异。
答案 10 :(得分:4)
我决定列出最具信息性的答案,因为这个问题变得有点拥挤。
DenverCoder8的替补标记显然值得一些认可以及Lucas的循环编译版本。 Tim Gee显示了pre&amp;和User377178强调了一些优点和缺点。和!=。 Tenacious Techhunter已经写过关于循环优化的文章,值得一提。
你有我的前5个答案。
答案 11 :(得分:4)
在这些情况下关心效率并不是一个好主意,因为你的编译器通常足够聪明,可以在能够实现时优化代码。
我曾为一家为安全关键系统生产软件的公司工作,其中一条规则是循环应以“&lt;”结尾。而不是!=。有几个很好的理由:
您的控制变量可能因某些问题或某些内存入侵而跳转到更高的值;
在维护中,可以在循环内增加迭代器值,或者执行类似“i + = 2”的操作,这样可以使循环永久滚动;
如果由于某种原因你的迭代器类型从“int”变为“float”(我不知道为什么有人会这样做,但无论如何......)浮点数的精确比较是一个不好的做法
(MISRA C ++编码标准(针对安全关键系统)也告诉你更喜欢规则6-5-2中的“&lt;”而不是“!=”。我不知道是否可以发帖这里的规则定义是因为MISRA是付费文件。)
关于++ i或i ++,我更愿意使用++ i。当您使用基本类型时,没有区别,但是当您使用STL迭代器时,preincrement更有效。所以我总是使用preincrement来适应它。
答案 12 :(得分:4)
我永远不会这样做:
for(int i = 0; i != 5; ++i)
i!= 5让它开放的可能性我将永远不会是5.它太容易跳过它并遇到无限循环或数组访问器错误。
++i
虽然很多人都知道你可以把++放在前面,但是很多人都没有。代码需要对人们可读,虽然它可能是一个微优化,以使代码更快,但当有人必须修改代码并说明为什么要完成时,真的不值得额外的头痛。
我认为道格拉斯·克罗克福德有最好的建议,那就是不要使用++或者。它有时候会变得太混乱(可能不是在一个循环中,但绝对是在其他地方)并且它很容易写i = i + 1.他认为这是一个坏习惯,离开,我有点看到一些残酷的“优化”代码后同意。
我认为crockford所面临的是那些运营商,你可以让人们写下这样的东西:
var x = 0;
var y = x++;
y = ++x * (Math.pow(++y, 2) * 3) * ++x;
alert(x * y);
//答案是54 btw。
答案 13 :(得分:3)
对于记录,“for”循环的cobol等价物是: -
PERFORM VARYING VAR1
FROM +1 BY +1
UNTIL VAR1 > +100
* SOME VERBOSE COBOL STATEMENTS HERE
END-PERFORM.
或
PERFORM ANOTHER-PARAGRAPH
VARYING VAR2 BY +1
UNTIL TERMINATING-CONDITION
WITH TEST AFTER.
这有很多变化。对于长期暴露于COBOL而未受损的人们来说,主要的问题是,默认情况下,UNTIL
实际上意味着WHILE
,即测试是在循环变量之前的循环顶部执行的。在处理循环体之前递增。您需要使用“WITH TEST AFTER
”才能使其成为正确的UNTIL
。
答案 14 :(得分:2)
关于可读性。作为一个喜欢Ruby的C#程序员,我最近为int编写了一个扩展方法,允许使用以下语法(如在Ruby中):
4.Times(x => MyAction(x));
答案 15 :(得分:2)
您的代码中洒满了数字文字?羞耻......
回到正轨,唐纳德克努特曾说过
我们应该忘记小事 效率,约占97% 时间:过早优化是 万恶之源。
所以,它真的归结为哪个更容易解析
所以......考虑到上述两种情况,以下哪一项程序员更容易解析?
for (int i = 0; i < myArray.Length; ++i)
for (int i = 0; i != myArray.Length; ++i)
编辑:我知道C#中的数组实现了System.Collections.IList接口,但在其他语言中并不一定如此。
答案 16 :(得分:2)
总结两种选择的利弊
优点!=
&lt;
的优点我的结论:
也许!= 版本应该在大多数情况下使用,当i是离散的时候,并且比较的另一面也不应该被篡改在环。
虽然&lt; 的存在将明确表示i是简单类型(或评估为简单类型)和但条件不是直截了当:在循环和/或并行处理中另外修改了i或条件。
答案 17 :(得分:2)
似乎没有人陈述原因为什么历史上preincrement运算符++i
优先于postfix i++
,对于小循环。
考虑前缀(increment和fetch)和后缀(fetch和increment)的典型实现:
// prefix form: increment and fetch
UPInt& UPInt::operator++()
{
*this += 1; // increment
return *this; // fetch
}
// posfix form: fetch and increment
const UPInt UPInt::operator++(int)
{
const UPInt oldValue = *this;
++(*this);
return oldValue;
}
请注意,前缀操作可以就地完成,其中后缀需要另一个变量来跟踪旧值。如果您不确定为什么会这样,请考虑以下事项:
int a = 0;
int b = a++; // b = 0, the old value, a = 1
在一个小循环中,后缀所需的额外分配理论上可以使它更慢,因此旧学校逻辑是前缀更有效。因此,许多C / C ++程序员都习惯使用前缀形式。
然而,其他地方指出的是现代编译器很聪明。他们注意到在for循环中使用postfix表单时,不需要后缀的返回值。因此,没有必要跟踪旧值并且可以对其进行优化 - 留下使用前缀表单获得的相同机器代码。
答案 18 :(得分:2)
第二个是不太可读,我想(如果只是因为“标准”练习似乎是前者)。
答案 19 :(得分:1)
嗯......只要不在for循环中修改i
,那就没问题了。真正的“最佳”语法完全取决于您想要的结果。
答案 20 :(得分:1)
FORTRAN的DO循环和BASIC的FOR循环实现了<
(实际上是<=
),用于正增量。不确定COBOL做了什么,但我怀疑它是相似的。所以这种方法对于像C这样的“新”语言的设计者和用户来说是“自然的”。
此外,<
比!=
更有可能在错误情况下终止,并且对整数和浮点值同样有效。
上面的第一点是风格开始的可能原因,第二点是继续风格的主要原因。
答案 21 :(得分:1)
我记得有一个代码段,由于某些错误导致i增加2而不是1,这导致它进入无限循环。因此,如第一个选项所示,最好有这个循环。这也更具可读性。因为i!= 5而i&lt; 5向读者传达了两种不同的含义。此外,如果你正在增加循环变量,那么i&lt; 5假设结束某个时间点,而i!= 5可能永远不会因为某些错误而结束。
答案 22 :(得分:1)
在许多体系结构中,检查某些东西是否为零更容易,它是否是其他任意整数,因此如果你真的想要优化某些东西,只要有可能就算 down ,而不是(这是ARM芯片上的example)。
一般来说,这实际上取决于你对数字和计数的看法。我正在做很多DSP和数学,所以从0到N-1计算对我来说更自然,在这方面你可能会有所不同。
答案 23 :(得分:1)
我使用发布的特定代码和整数看到了大量答案。但问题是'for loops'特有的,而不是原帖中提到的具体问题。
我更喜欢使用前缀增量/减量运算符,因为它几乎可以保证与后缀运算符一样快,但与非基本类型一起使用时可能更快。对于像整数这样的类型,任何现代编译器都不会有问题,但是如果你习惯使用前缀运算符,那么在它将提供速度提升的情况下,你将从中受益。
我最近在一个大型项目上运行了一个静态分析工具(可能大约1-2百万行代码),并且发现大约80个案例中使用了后缀,前缀可以提供速度优势。在大多数情况下,好处很小,因为容器的大小或循环次数通常很小,但在其他情况下,它可能会超过500多个项目。
根据递增/递减的对象类型,当发生后缀时,也可能发生复制。我很想知道当没有引用其值时使用后缀时会有多少编译器会发现这种情况,因此无法使用该副本。它会在这种情况下为前缀生成代码吗?甚至静态分析工具也提到它发现的80个案例中的一些可能会被优化,但为什么要抓住机会并让编译器决定呢?我没有发现前缀运算符在单独使用时会让人感到困惑,它只会在开始使用时内联,作为逻辑语句的一部分时成为读取的负担:
int i = 5;
i = ++i * 3;
简单的逻辑不应该考虑运算符优先级。
int i = 5;
i++;
i *= 3;
确定上面的代码需要额外的一行,但它读得更清楚。但是对于for循环,被改变的变量是它自己的语句,所以你不必担心它的前缀或后缀,就像在上面的代码块中一样,i++
是唯一的,所以很少有人想到需要关于它会发生什么,所以下面的代码块可能只是可读:
int i = 5;
++i;
i *= 3;
正如我所说,这并不重要,但是在不使用变量时使用前缀,否则在同一语句中使用前缀在我看来只是一个好习惯,因为在某些时候你会在非原始类上使用它,你可以保存自己的复制操作。
只是我的两分钱。
答案 24 :(得分:1)
最终,关于什么更有效的决定因素既不是语言也不是编译器,而是底层硬件。如果您正在为嵌入式微控制器编写代码,如8051,向上计数与向下计数,大于或小于与不等于,以及递增与递减,可以对性能产生影响,在你的循环的非常有限的时间范围内。
虽然足够的语言和编译器支持可以(并且通常会)减少以最佳但在概念上等效的方式实现指定代码所需的指令的缺失,但编码硬件本身保证性能,而不仅仅是希望在编译时存在足够的优化。
所有这些意味着,你的问题没有一个通用的答案,因为那里有很多不同的低端微控制器。
然而,更多更重要的是,优化你的for循环迭代,循环和中断的方式,正在修改它在每次迭代中的作用。如果导致for循环,则每次迭代都会在中保存两个或更多指令,执行!您将获得一个或多个周期的净增益!对于真正优化的代码,您必须权衡完全优化for循环如何迭代每次迭代所发生的事情的后果。所有这一切,一个好的经验法则是,如果你发现记住你的特定目标硬件的所有装配说明是一个挑战,那么“for”循环的所有变化的最佳装配指令可能是完全占了。你可以随时检查你是否真的在乎。
答案 25 :(得分:1)
我们可以再使用一个技巧。
表示(i = 5; i> 0; i - )
我想大多数编译器都会像这样优化循环。 我不确定。有人请验证。
答案 26 :(得分:1)
我认为最终归结为个人偏好
我喜欢这个想法for(int i = 0; i < 5; i++)
在
for(int i = 0; i != 5; ++i)
由于某些原因我有可能超过5的价值。我知道大多数时候发生这种情况的可能性很小,但我认为最终它的良好做法。
答案 27 :(得分:1)
当我第一次开始用C语言编程时,我在for循环中使用++i
形式只是因为我当时使用的C编译器没有做太多优化,并且在这种情况下会生成稍微更高效的代码。
现在我使用++i
表单,因为它读作“increment i”,而i++
读作“i is increment”,任何英语老师都会告诉你避免被动语态。
最重要的是做一些看起来更具可读性的内容。
答案 28 :(得分:1)
如果您的索引不是int
,而是(比如说)C ++类,那么第二个示例可能会更有效。
然而,正如所写,你认为第二种形式更有效率的信念是完全错误的。任何体面的编译器都会有一个简单的for循环的优秀的codegen惯用语,并且可以为这两个例子生成高质量的代码。更重要的是:
在一个正在进行重度性能关键计算的for循环中,索引算法几乎可以忽略整个负载。
如果你的for循环对性能至关重要而且没有进行繁重的计算,这样索引算法实际上很重要,你几乎肯定会重构你的代码,以便在循环的每次传递中做更多的工作。
答案 29 :(得分:0)
实际上有更多的“历史”原因早于Tim Gee提供的C ++示例:机制起源于具有前后增量寄存器指令且C语言最初打算生成的机器上的C “编码到机器”比使用汇编语言更容易维护。
虽然许多当前的编译器确实可以经常删除任何额外的副本,但最好是根据您的特定环境和要求学习语言和选择操作,而不是盲目地跟随其他人实例
对于它的价值,我会将循环索引定义为 unsigned 而不是 int ,因为它更好地定义了一个简单循环计数器的有效域,并且如果 i 的价值变得消极......
特别是在C的情况下,参考的基础语言,由于它提供的安全性,并且因为机器被优化用于进行寄存器(整数)值比较,因此排序比较器是有意义的,但它也实现了主要是因为使用从零开始的数组索引的习语。
使用 i!= length 实际上是一个错误,因为您需要编码 i!=(length - 1)。这当然是非常低效的,因为你需要预先计算并将(length - 1)存储在一个临时变量中,从而“浪费”一个宝贵的寄存器资源,否则你最终会重新计算它每次循环比较 - 更糟糕的 faux pas !
更重要的是,我正在回答这个问题,因为我认为对这个问题的“最佳”答案的“奖励”是毫无意义的。重要的是避免尝试定义基于主题的“全球”解决方案,这些主题经常是“火焰战争”或“宗教战争”的主题,因为它们曾经在论坛中被调用过。为什么呢?
如果您花费大量时间研究C ++中的模板习惯用法或C#和Java中的泛型,您将了解到排序和相等比较器并不总是基本的。根据排序运算符定义(in)相等运算符是很常见的,因为它们通常是使用STL或通用容器所必需的。在那些环境中,假设您可以定义 “最有效”的源语法,以便在从C库派生的所有语言中使用,这是非常危险的,您必须仔细决定当您利用预定义算法时要使用哪些比较。
迭代器循环的语法中的“更改”是基于希望对所有迭代器使用相同的语法,并且排序比较器根本不适用于除了伪装成迭代器的数组指针之外的任何东西 - 这是唯一的场景连续访问的容器元素保证存储在具有单调递增地址的连续内存中。
如果效率真的对您很重要,如原始问题所述,衡量(个人资料)并根据数据优化您的使用情况。最初的“信念”陈述是无关紧要的 - 衡量......并且不要假设你在某个环境中得出的结论对于其他所有人来说都是合理的。
如果源代码的一致性是您所追求的,请查看来自不同组织的任意数量的编码建议,并根据自己的喜好选择一个 - 只需准备好发现许多编码“标准”与其他标准基本正交......简而言之,这是愚蠢运动部的一个问题: - /
答案 30 :(得分:0)
使用它不是好方法!= 5.但是
for (int i =0; i<index; ++i)
比
更有效for(int i=0; i<index; i++)
因为i ++首先执行复制操作。有关详细信息,您可以在C ++中查看运算符重载。