++i
而不是 i++
,这是有原因的吗?Possible Duplicate: Is there a performance difference between i++ and ++i in C++?
++i
而不是 i++
,这是有原因的吗?++i
的语义略微更高效:
++i; // Fetch i, increment it, and return it
i++; // Fetch i, copy it, increment i, return copy
对于类似于整数的索引,效率提升最小(如果有的话)。对于迭代器和其他较重的对象,避免复制可以是一个真正的优势(特别是如果循环体内没有太多的工作)。
例如,考虑使用提供任意精度整数(因此具有类似于向量的内部结构)的理论BigInteger类的以下循环:
std::vector<BigInteger> vec;
for (BigInteger i = 0; i < 99999999L; i++) {
vec.push_back(i);
}
在这个循环中,i++ 操作包括了拷贝构造(即 operator new, 逐位数字拷贝)和析构(operator delete)。而这个循环本质上只会多做一次索引对象的拷贝。所以,使用后缀增量运算符 i++ 而不是前缀增量运算符 ++i,实际上会让程序多做一倍的工作(并且很可能会增加内存碎片化)。
对于整数而言,前置和后置自增没有区别。
如果i
是一个非平凡类的对象,则通常更喜欢使用++i
,因为对象会先被修改然后再进行计算,而i++
则是在计算之后再进行修改,因此需要进行复制。
++i
,以便您养成使用它的习惯。 - SingleNegationEliminationi++
有点成为惯用语;如果你经常使用这两种语言,可能会感到困惑... - Oliver Charlesworthi
是某个类的实例,该类重载了递增运算符。您是说,如果我只是后置递增(不在循环控制语句中,而是仅递增它)(即i ++;
),编译器将无法看到我没有使用返回值,并自动重新编写为++ i
? - Jim Mischeloperator++()
和后自增operator++(int)
)。如果它们实际上是等价的,并且如果调用是内联的,并且涉及到的复制都被优化器移除,那么生成的代码可能会相同-可以尝试一下。但是编译器肯定不能仅基于结果未使用就将其中一个替换为另一个。我并不特别在意,因为我写++i
以明确我的意图。“increment i” -> “++i”。 - Steve Jessop++i
是前缀递增,i++
是后缀递增。
后缀递增的缺点是它会生成一个额外的值;它返回旧值的副本,同时修改i
。因此,在可能的情况下应避免使用后缀递增。
对于整数,使用哪个都可以。
如果循环变量是一个类/对象,这可能会有所不同(只有通过性能分析才能告诉您是否存在显着的差异),因为后缀递增版本要求您创建一个被丢弃的该对象的副本。
如果创建该副本是一个昂贵的操作,那么您每次通过循环都必须支付一次这样的费用,而没有任何理由。
如果您习惯于在for循环中始终使用++i
,那么您不需要停下来思考在特定情况下您正在做什么。您总是这样做。
这是由于性能原因:i++ 生成了一个副本,如果您立即丢弃它,这是一种浪费。当然,如果 i 是原始类型,编译器可以优化掉这个副本,但如果不是,则不能。请参见此问题。
++i
和i++
的性能完全相同。 - John Dibling任何值得一用的编译器在运行时都不会因为操作系统或硬件平台而有所不同。
for(int i=0; i<10; i++)
and
for(int i=0;i<10;++i)
++i和i++的成本是相同的。唯一不同的是,++i的返回值为i+1,而i++的返回值为i。
因此,对于那些更喜欢使用++i的人来说,可能没有合理的理由,这只是个人喜好。
编辑:对于类来说,这是错误的,如其他每篇帖子所说。如果i是一个类,i++会生成一个副本。
正如其他人已经指出的那样,对于用户定义类型,前置递增通常比后置递增更快。为了理解这是为什么,看一下实现两个运算符的典型代码模式:
Foo& operator++()
{
some_member.increase();
return *this;
}
Foo operator++(int dummy_parameter_indicating_postfix)
{
Foo copy(*this);
++(*this);
return copy;
}
如您所见,前缀版本只是修改对象并通过引用返回它。
另一方面,后缀版本必须在实际增量执行之前进行复制,然后将该副本按值复制回调用者。从源代码可以明显看出后缀版本必须做更多的工作,因为它包括对前缀版本的调用:++(*this);
对于内置类型,只要您丢弃该值,即只要不在较大的表达式中嵌入++i
或i++
,例如a = ++i
或b = i++
,就没有任何区别。
copy
的靶子——未使用的值没有副作用。++i
确实可以避免你想知道优化是否成功,更重要的是它显然更有意义;-) - Steve Jessop当您使用后缀运算符时,它会在内存中实例化一个对象。有些人认为在for循环中使用后缀运算符更好。
个人喜好。
通常来说,有时候这很重要,但是不想显得像个自大的人,如果你必须问的话,那可能并不重要。