57

可能重复:
C++ 中的 i++ 和 ++i 之间是否存在性能差异?

是否有一些程序员++i在正常的 for 循环中编写而不是编写的原因i++

4

9 回答 9

128

++i由于其语义,效率稍高:

++i;  // Fetch i, increment it, and return it
i++;  // Fetch i, copy it, increment i, return copy

对于类似 int 的索引,效率增益是最小的(如果有的话)。对于迭代器和其他重量较重的对象,避免该副本可能是一个真正的胜利(特别是如果循环体不包含太多工作)。

例如,考虑以下循环,使用理论 BigInteger 类提供任意精度整数(以及某种类似矢量的内部结构):

std::vector<BigInteger> vec;
for (BigInteger i = 0; i < 99999999L; i++) {
  vec.push_back(i);
}

i++ 操作包括复制构造(即操作符 new,逐位复制)和破坏(操作符删除),用于一个循环,除了本质上再制作一个索引对象的副本之外,它不会做任何事情。本质上,您只需使用前缀就足够的后缀增量,就可以将要完成的工作加倍(并且很可能会增加内存碎片)。

于 2010-11-23T22:41:04.117 回答
89

对于整数,前增量和后增量之间没有区别。

如果i是一个非平凡类的对象,那么++i通常是首选的,因为该对象被修改然后评估,而i++在评估之后修改,因此需要制作副本。

于 2010-11-23T22:40:58.850 回答
10

++i是一个预增量;i++是后增量。
后增量的缺点是它会产生额外的价值。它在修改时返回旧值的副本i。因此,您应该尽可能避免它。

于 2010-11-23T22:40:37.227 回答
5

对于整数,这是首选。

如果循环变量是一个类/对象,它可以产生影响(只有分析可以告诉你它是否是一个显着的差异),因为后增量版本要求你创建一个被丢弃的对象的副本。

如果创建该副本是一项昂贵的操作,那么您每次通过循环都要支付一次费用,完全没有理由。

如果您养成始终使用++iin for 循环的习惯,则无需停下来思考在这种特殊情况下所做的事情是否有意义。你总是这样。

于 2010-11-23T22:44:02.650 回答
3

没有哪个编译器值得在盐中发挥作用

for(int i=0; i<10; i++)

for(int i=0;i<10;++i)

++i 和 i++ 具有相同的成本。唯一不同的是 ++i 的返回值是 i+1 而 i++ 的返回值是 i。

所以对于那些喜欢 ++i 的人来说,可能没有有效的理由,只是个人喜好。

编辑:这对班级来说是错误的,正如在其他所有帖子中所说的那样。如果 i 是一个类, i++ 将生成一个副本。

于 2010-11-23T22:39:48.797 回答
3

这是有原因的:性能。i++ 生成一个副本,如果您立即丢弃它,那是一种浪费。当然,如果是原语,编译器可以优化掉这个副本i,但如果不是,则不能。看到这个问题。

于 2010-11-23T22:41:24.487 回答
2

正如其他人已经指出的那样,对于用户定义的类型,预增量通常比后增量更快。要了解为什么会这样,请查看实现这两个运算符的典型代码模式:

Foo& operator++()
{
    some_member.increase();
    return *this;
}

Foo operator++(int dummy_parameter_indicating_postfix)
{
    Foo copy(*this);
    ++(*this);
    return copy;
}

如您所见,前缀版本只是简单地修改对象并通过引用返回它。

另一方面,后缀版本必须在执行实际增量之前进行复制,然后将该副本按值复制回调用者。从源代码中可以明显看出后缀版本必须做更多的工作,因为它包含对前缀版本的调用:++(*this);

对于内置类型,只要您丢弃该值,即只要您不嵌入++ii++在更大的表达式(如a = ++ior )中,它就没有任何区别b = i++

于 2010-11-23T22:51:29.920 回答
1

当您使用后缀时,它会在内存中实例化更多对象。有人说在for循环中使用后缀操作符比较好

于 2010-11-23T22:40:04.357 回答
0

个人喜好。

通常。有时这很重要,但不要在这里看起来像个混蛋,但如果你不得不问,它可能不会。

于 2010-11-23T22:38:30.380 回答