【问题标题】:Does *&++i cause undefined behaviour in C++03?*&++i 会在 C++03 中导致未定义的行为吗?
【发布时间】:2015-04-12 11:02:05
【问题描述】:

another answer 中指出,在C++11 之前,其中iint,然后使用表达式:

*&++i

导致未定义的行为。这是真的吗?

在另一个答案中,在 cmets 中进行了一些讨论,但似乎没有说服力。

【问题讨论】:

  • 在这个答案中,知识渊博的“Johannes Schaub - litb”认为这是一个不真实的陈述。并没有得到任何回应。
  • @DrewDormann James Kanze 也很博学
  • *&i 完全有效,++i 返回对i 的引用,所以我自己看不到问题...
  • 未定义的行为问题是否会出现在 i = *&++i 或只是 *&++i 本身?
  • @JonathanPotter:这不是未定义的行为,但它确实评估为未定义的值。他们都是对的,他们只是在谈论微妙的不同事物。

标签: c++ language-lawyer undefined-behavior c++03 sequence-points


【解决方案1】:

我认为这个问题只有在我们处理表达式时才有意义:

i = *&++i;

C++03 标准中的相关引用是 [expr]/4:

除非另有说明,否则单个运算符的操作数和单个子表达式的求值顺序 表达式和副作用发生的顺序是未指定的。上一个之间 并且下一个序列点标量对象的存储值最多只能通过评估修改一次 的一种表达方式。此外,只能访问先前值以确定要存储的值。 对于完整的子表达式的每个允许排序,都应满足本段的要求 表达;否则行为未定义。

i = ++i + 1; // the behavior is unspecified

我们可以比较i = *&++ii = ++i + 1 的顺序,以确定相同的规则导致两者都未指定。它们都是以下形式的陈述:

i = f(++i);

对于任何函数f,左侧的i 的读数和右侧的++i 的副作用没有相对顺序。因此,未定义的行为。

【讨论】:

    【解决方案2】:

    *&++i 本身是否有 UB 是没有意义的。延迟不一定访问i 的存储值(之前的或新的),正如您可以通过使用它作为引用的初始化表达式看到的那样。只有在涉及右值转换(在这种情况下使用)时,才有任何问题需要讨论。然后,因为我们可以使用++i 的值,所以我们可以使用*&++i 的值,但注意事项与++i 完全相同。

    原来的问题本质上是i = ++i,和i = *&++i是一样的。这是 C++03 中未定义的行为,因为 i 在序列点之间被修改了两次,并且在 C++11 中定义良好,因为赋值运算符的副作用在值计算之后被排序左右两边。

    可能需要注意的是,C++98 和 C++03 标准中的非规范示例是不正确的,将一些形式上未定义的行为描述为仅仅是未指定的行为。因此,意图一直没有完全清楚,一路回来。一个好的经验法则是根本不依赖于语言的这种晦涩的角落案例,以避免它们:不需要成为语言律师就可以理解代码......

    【讨论】:

    • AFAICS i = ++i 在 C++03 中得到了很好的定义,正如链接的 Q/A 中接受的答案所正确显示的那样。
    • @Columbo:如果您愿意总结或引用,我将努力反驳您所看到的说法。我找不到它,对不起。但是,由于这在 C++03 中非常简单,绝对不要在序列点之间修改两次或更多,可能您不需要更多? [expr] 中的 C++03 §5/4:“在前一个和下一个序列点之间,一个标量对象的存储值最多只能通过表达式的评估修改一次。”
    • 显然我完全误解了序列点的概念。我认为answer 引用的段落足以证明该表达式的明确性。但是那里没有任何关于序列点的说法(我认为它们的存在是暗示,但事后看来这是错误的)。事实上,它们似乎很少出现,它们定义了许多概念上很好的代码来调用 UB。幸运的是,这已在 C++11 中修复。
    • @Columbo:哦。 C++03 序列点本质上是语句之间的点(但考虑到函数调用,它变得更加复杂)。 C++03 §1.9/7 “在称为 sequence points 的执行序列中的某些指定点,先前评估的所有副作用都应完成,后续评估的副作用不应发生。”和第 1.9/16 节“在完成每个完整表达式的评估时有一个序列点”,以及第 1.9/17 节中有关函数调用的更多信息。 AFAICS 您链接到的答案没有提到序列点或 C++03。
    • 我明白什么是序列点。我只是不知道它们的存在必须明确说明,即赋值运算符的操作数的评估和赋值本身之间没有序列点,因为它没有在任何地方注明。
    猜你喜欢
    • 2011-04-25
    • 2014-08-11
    • 2016-09-04
    • 1970-01-01
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    相关资源
    最近更新 更多