i++ 或 ++i 哪个更有效?[复制]

IT小君   2021-10-08T22:18:48
评论(20)
IT小君

我++:

  • 创建 i 的临时副本
  • 增量 i
  • 返回临时副本

++我:

  • 增量 i
  • 返回我

通过优化,结果程序集很可能是相同的,但是 ++i 效率更高。

编辑:请记住,在 C++ 中,我可能是支持前缀和后缀 ++ 运算符的任何对象。对于复杂对象,临时复制成本是不可忽略的。

2021-10-08T22:18:49   回复
IT小君

我会在别处寻找优化潜力。

2021-10-08T22:18:49   回复
IT小君

效率不应该是你关心的:它是意义两者是一样的,除非它们是独立的:一个操作值的预使用,另一个操作。

国际我; 我 = 1; cout << i++; //返回1

国际我; 我 = 1; cout<<++i; //返回2

当意义不重要时,大多数编译器会将 ++i 和 i++(例如在 for 循环中)翻译成相同的机器/VM 代码。

2021-10-08T22:18:49   回复
IT小君

在现代编译器上无关紧要。

int v = i++;  

是相同的

int v = i;
i = i + 1;

现代编译器会发现它v是未使用的,并且要计算的代码v是纯的(没有副作用)。然后它将删除v和分配代码并生成这个

i = i + 1;
2021-10-08T22:18:49   回复
IT小君

这非常重要!特别是如果你在 C++ 领域使用自定义迭代器协议......

++i // the prefered way, unless..
auto j = i++ // this is what you need

您应该使用前缀表示法来避免必要的复制开销,但它仅适用于迭代器,不适用于内置本机类型,无论如何这些都只是一条指令。

2021-10-08T22:18:49   回复
IT小君

++i 对于 operator++ 的非平凡实现可能更有效,但即使在这种情况下,编译器也可以优化掉中间临时。

2021-10-08T22:18:50   回复
IT小君

++i 不需要临时变量来存储内容。可以这样想:

++我

int preIncrement(int i)
{
    i = i + 1;
    return i;
}

我++

int i = 5; // as an example
int postIncrement(_i)
{
    int temp = _i;
    i = _i + 1;
    return temp;
}

看?后增量需要一个临时变量。假设编译器没有为您解决所有问题,它几乎可以肯定会这样做。

当然,更重要的是程序逻辑;如果你太担心这个,你就有可能遇到微优化剧院的悲惨悲剧......:)

2021-10-08T22:18:50   回复
IT小君

好吧,在 C++ 中,我相信它们有不同的用途,具体取决于您希望何时更新变量。

效率不应该决定您何时使用一种而不是另一种,但我认为无论哪种方式它们都具有相同的效率。

2021-10-08T22:18:50   回复
IT小君

除非我遗漏了什么,否则它们应该具有相同的效率。它们都应该导致单个添加指令。这只是添加指令发生位置的问题:在代码行的开头或结尾。

2021-10-08T22:18:50   回复
IT小君

++i更快,因为i++必须存储i,然后将其递增,然后返回 的存储值i++i简单地增加i然后返回它。

// ++i
i += 1;
return i;

// i++
temp = i;
i += 1;
return temp;
2021-10-08T22:18:50   回复
IT小君

一个独立的“i++;” 或 "++i;" 应该生成同样高效的代码。如果您在“副作用”发挥作用的表达式中使用它,则不同。

也就是说,曾经有一段时间,当“全世界都是一个 Vax”并且编译器很烂时,据说 ++i 比 i++ 更有效,即使在“for (i = 0; i < N; + +i)”类型设置。

2021-10-08T22:18:50   回复
IT小君

一般来说,使用 ++i 比使用 i++ 更有效率。这样做的简单原因是 ++i 与

我 += 1;

对于 x86,这是一条指令(可能也是大多数其他广泛使用的架构)。i++ 然而等于

tmp = i; 我 += 1;

那是因为 'i' 的旧值是 i++ 的计算结果。显然,这需要做更多的工作,而不仅仅是 i += 1;

但是如上所述,这对足够聪明的编译器几乎没有影响,因为它将优化未使用的操作。对于许多解释型语言(例如:PHP),++i 的速度提升可能很小;但这种增长是微不足道的。

2021-10-08T22:18:51   回复
IT小君

输入 i++ 通常更容易,因此在生产力时间方面更有效。

不过,说真的,如果i是本机数据类型(例如 int、double 等)——没有区别。

如果它是用户定义的类型,则取决于实现,例如

class Type
{
    Type& operator ++(){}
    const Type& operator ++(int i){}
};  

T i;
2021-10-08T22:18:51   回复
IT小君

在没有优化的情况下,++i 在 x86 汇编中比 i++ 少一条处理器指令。

2021-10-08T22:18:51   回复
IT小君

没有区别。使用最有意义的结构。

如果您的应用程序运行缓慢,我可以向您保证,它永远不会因为整数增量操作的速度差异。如果是,则是编译器中的严重错误。应用程序中的速度问题将是算法效率低下、等待 I/O 等。

不要担心您没有的问题。过早优化是万恶之源

2021-10-08T22:18:51   回复
IT小君

这个堆栈溢出问题有一个很好的答案:C 中的 i++ 和 ++i 之间有性能差异吗?

我想补充一点,您应该使用更适合您需求的任何一种。除了在最关键的应用程序中,它并不重要。从学术的角度来看,最好编写表达您需要的代码并最终进行优化。

2021-10-08T22:18:51   回复
IT小君

没有正确或错误的答案。

因为它取决于:

  1. 编译器是如何实现的。

  2. 系统运行在什么 CPU 上。

  3. 如果i是字节或i双字

2021-10-08T22:18:52   回复
IT小君

这取决于上下文,例如:

x = i++

在这种情况下,'x' 将等于 'i',只有在此之后,'i' 才会增加 1。

x = ++i

在这种情况下,'i' 将增加 1,然后将 'x' 的新值分配给 'x'。

在“for”循环的情况下,除了性能(++i 更快)之外,几乎没有明显的区别。

2021-10-08T22:18:52   回复
IT小君

一般在C++中,postfix会要求对对象进行额外的构造递增,而prefix则是直接应用于对象。(或者我读过。)

由于我对此事的了解有限,我无法证明编译器如何处理它,因此可以为您处理它,使其成为一个有争议的问题。

2021-10-08T22:18:52   回复
IT小君

很难准确回答这个问题,因为它取决于编译器/解释器的实现。

但一般来说你可以大致说一下将 i++ 扩展到以下指令:

COPY i to tmp
INCREMENT tmp
SAVE tmp as i

而 ++i 将大致扩展到:

LOAD i
INCREMENT i

你不能只说 ++i 比 i++ 快,因为语言实现非常聪明,当你知道你不会访问 i++ 的临时值时,它们可以优化这些指令。这通常发生在 for 循环中。所以在很多情况下它是一样的。

如果您正在尝试这些类型的微优化,我建议您在选择一个之前进行分析/测量。

2021-10-08T22:18:52   回复