【问题标题】:Code style in C (and C++) loops: postfix and prefix incrementsC(和 C++)循环中的代码样式:后缀和前缀增量
【发布时间】:2020-08-10 20:06:22
【问题描述】:

这些天我经常看到这种情况:

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

而不是 - 就像 20 年前的时尚(?)那样 - 这个:

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

这种变化是有原因的还是只是时尚?

(这里有一个关于 Java 的类似问题,但我认为答案没有触及问题的核心)

【问题讨论】:

  • 在 C++ 中,预增量是首选,因为对于非原始类型,它避免构造对象旧状态的副本。
  • 相关(不重复):stackoverflow.com/questions/1783822/….
  • @jamesdlin - 有机会得到更全面的答复:我根本没想到。
  • fwiw,早在 20 年前,++i 应该是首选,这没有什么实质性的改变
  • 自 1992 年以来我一直在专业地使用 C++。对于 for 循环中的 int,我总是编写我 30 年前学习的简单、规范的版本 i++。对于迭代器,我需要使用 preincrement 版本来提高效率,即 ++it.

标签: c++ c loops


【解决方案1】:

这主要是时尚,但也是一致性和误解的结合。

当迭代器出现时,越来越多的人开始意识到 ++it 可能比 it++ 便宜,对于一些比指针更复杂的迭代器 it,他们开始养成在任何地方进行预增量,以在后增量的语义中保存他们认为不必要的副本(原始值必须临时存储以便在增量发生后返回)。然后他们也会对整数这样做,因为为什么不呢?

实际上,没有什么可保存的。您的编译器完全能够发现此处从未使用过评估结果,因此++itit++ 在这种情况下具有完全相同的语义(除非在运算符的定义中存在一些非惯用的副作用)。对于简单整数i 尤其如此。

当然,这并没有什么坏处,而且它确实消除了您错过一些奇怪的角度的风险,确实会导致不必要的副本。这是一个很好的做法。只是它的出现并非出于必要。

【讨论】:

    【解决方案2】:

    C 和 C++

    后增量涉及可以通过使用前增量 (Post-increment and Pre-increment concept?) 避免的临时。

    C++

    如果只涉及整数,则问题不是那么严重,编译器可能会优化两个版本以实现基本相同的功能。但是,在 C++ 中,基本上任何类类型的对象都可以有一个 ++(后置和前置),并且基本上可以重载以执行任何操作。对大对象进行后增量是有代价的,并且取决于如何实现运算符,编译器可能无法同时优化后增量和前增量来做本质上相同的事情。为了安全起见,最好使用++i

    20 年前

    实际上,与此问题相关的唯一变化是编译器优化随着时间的推移变得更好。我没有检查任何旧编译器,但我会说 20 年前缺少编译器优化是使用 ++i 而不是 i++ 的更强有力的理由。也许您观察到的只是代码风格变得更好。

    【讨论】:

    • 这个答案忽略了一个事实,即这里肯定没有“成本”。考虑到所有因素,语义是完全等效的(因为未使用评估结果),并且生成的代码将是相同的。这更多是为了保持一致性,最有可能的是,还有误解(人们认为这会节省他们的表现)
    • @AsteroidsWithWings 不在 C++ 中,++ 在用作前增量或后增量时可能会以不同方式重载。我认为真正的原因是 ++i 在 C++ 中很常见(因为这种差异 + 优化甚至过早优化)和 i++ 在 C 代码中很常见,因为它根本没有问题。跨度>
    • @larkey 查找“as-if”规则。在编写 C++ 时,您并没有指定计算机要执行的指令序列。您正在描述一个程序。如果不使用后增量的评估结果,则不需要中间结果,并且您的编译器足够聪明,可以实现这一点。 (有些人称之为“优化”。)如果有一个单一的过载,但是,有副作用,那么是的,必须执行这些副作用,我在我的回答中确实说过;)你不能超载之前或int 的后增量。
    • @AsteroidsWithWings 我只阅读了您的评论,其中说语义是等价的,如果您以某种方式重载会产生副作用,则不需要在 C++ 中为所有类型保留。这样,无论表达式的忽略评估如何,语义都是不同的。因此,您在 C++ 中有这种区别,但在 C 中没有。
    • @larkey 确实;我就是这么说的。
    猜你喜欢
    • 2014-08-11
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    • 2017-08-04
    • 2014-05-15
    • 1970-01-01
    相关资源
    最近更新 更多