【问题标题】:why ++++i regular but i++++ not regular in C++?为什么 ++++i 常规但 i++++ 在 C++ 中不常规?
【发布时间】:2011-08-24 15:42:46
【问题描述】:

当我使用i++++ 时出现编译错误:

for (int i=1;i<=10;i++++) {} //a.cpp:63: error: lvalue required as increment operand

int i = 0;
i++++; // a.cpp:65: error: lvalue required as increment operand

但是当我使用++++i 时,它正在工作。任何人都可以解释一下为什么++++i 正常但i++++ 不正常?

谢谢。

【问题讨论】:

  • ++++i 等价于 (i=(i+=1)+1) 但这无济于事。
  • i+=2为您节省了一个字符,并且有效。试试看!

标签: c++


【解决方案1】:

由于x 的类型是内置原始类型,因此两个表达式都会调用未定义的行为,因为它们都尝试在两个序列点之间修改相同 对象两次。

不要这样做。

阅读此常见问题解答:

Undefined behavior and sequence points


但是,如果 x 的类型是用户定义的类型,并且您已经为这两个表达式重载了 operator++,那么两者都是良好定义的

对此,请参阅此主题以了解说明和详细信息:

Undefined behavior and sequence points reloaded

【讨论】:

  • 等等,为什么前置增量是一个UB?
  • @Xeo:两者都尝试在两个序列点之间修改对象两次
  • ++++x 不是作为x.operator++().operator++() 实现的,因此不是 UB?
  • @Xeo: x 不是用户定义的类型!
  • @Nawaz:Nono,只是编译器开发人员可以这样做。但似乎我错了,原始类型的两个增量之间没有排序。
【解决方案2】:

C++ 标准在 5.2.6 节中说 i++ 的结果是可修改的左值,而在 5.3.2 中 ++i 的结果是可修改的左值。这可以帮助解释为什么 i++++ 和 ++++i 不需要生成诊断信息,并且有时似乎可以工作。

但是,++++i 在前一个和下一个序列点之间修改了 i 两次,因此结果仍然是未定义的行为。 ++++i 可以工作,但不是必须的。

幸运的是,您的编译器诊断出 i++++。

【讨论】:

  • 由于我只能访问 C++0x FDIS,这是否改变了?因为 FDIS 的 5.2.6 表示 i++ 的结果是 (p) 右值,并且仅将操作数 (i) 视为可修改的左值。
  • 我有 2003 年的版本。C99 做同样的事情,但措辞更少。如果它改变了,那么改变一定是前一段时间了。
  • 好的,所以i++++ 在 C++98/03 中应该是有效的(但 UB),但在 C++0x/11 中肯定是无效的。
  • 供您参考,当前标准here 的最终草案中的 5.2.6 声明 结果是一个右值
  • n3290 表示 i++(i 是原始类型)的结果是纯右值。所以你的答案是有缺陷的!
【解决方案3】:

因为运营商的概念“签名”是:

​T& operator ++(T& a);​     // pre
​T operator ++(T& a, int);​ // post
                          // note the int is solely to distinguish the two

一个返回引用(左值),另一个不返回。但是,两者都将引用作为参数,因此返回引用的那个 (++i) 可以被链接,而没有返回引用的那个 (i++) 不能。

请注意,正如@Nawaz 所说,有效的会调用未定义的行为,即使在假设中有效的行为也会调用未定义的行为。

【讨论】:

  • 问题中的type是内置类型。所以operator++ 不会出现在图片中。
  • @Nawaz - 我将其用于说明目的。我知道内置类型不会使用 operator++ 做任何事情,但查看签名有助于理解问题。
  • 如果内置类型没有operator++,那怎么能说明问题呢?如果说明的对象本身是错误的,那它怎么能正确说明任何事情呢?
【解决方案4】:

正如某些人所说,++++i 被您的编译器接受,但是当它被评估时,它会在 C++03 中产生未定义的行为。

请注意,简单地说sizeof(++++i) 是可以的,因为没有评估任何内容。在 C++11 中说 ++++i 很好,即使它被评估了。

【讨论】:

    【解决方案5】:

    从“你想做什么”的角度来回答这个问题:首先调用i++++ 是没有意义的,因为i++ 确实返回对递增@ 的引用987654323@ 变量,但值i 增加了。所以i++++ 基本上会这样做:

    1. 复制i到一个临时变量t
    2. 递增i
    3. 复制t到一个临时变量u
    4. 递增t
    5. 扔掉tu

    所以剩下的就是i的一个增量。

    另一方面,++++i 确实很简单

    1. 递增i
    2. 再次增加i

    这确实很有用,不是整数类型,而是当i 是非随机访问迭代器时肯定有用,因为那样你就不能依赖i+=2

    【讨论】:

      猜你喜欢
      • 2014-09-15
      • 1970-01-01
      • 2021-09-26
      • 2014-09-04
      • 1970-01-01
      • 2015-09-18
      • 2011-10-06
      • 2019-04-26
      相关资源
      最近更新 更多