You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于C++17中sequence points变更及合法表达式的技术问询

C++17 Changes to Evaluation Order & Side Effects (Replacing "Sequence Points")

Great question! This is a super common point of confusion, especially since messy patterns like i = i++ still get asked about constantly—even though they’re terrible practice. Let’s break down what changed in C++17, including which once-undefined expressions now have predictable behavior.

First: The Terminology Shift

Gone are the days of "sequence points"—since C11, the standard has moved to a more granular model using sequenced before, sequenced after, and indeterminately sequenced relationships. C17 refined this model even further, making evaluation rules more predictable for many common expressions. This new terminology is far more precise than the old "sequence points" concept.

Key C++17 Changes to Evaluation Order

Here are the most impactful updates related to side effects and evaluation order:

1. Defined Order for Binary Shift Operators

For expressions like a << b or a >> b, C++17 now mandates that:

  • The left operand (a) is fully evaluated, and all its side effects are completed, before the right operand (b) is evaluated.
  • Before C++17, the order was indeterminately sequenced—meaning a compiler could evaluate a or b first, leading to undefined behavior if one operand modified a variable used in the other.

Example:

int x = 2;
int result = x << (x++); // C++17: x is 2 first, then incremented to 3. Result is 2 << 2 = 4.
                         // Pre-C++17: Undefined behavior

2. Strict Sequence for Assignment Operators

For all assignment operators (=, +=, -=, etc.), C++17 defines a clear, step-by-step sequence:

  1. Fully evaluate the right operand, and complete all its side effects.
  2. Evaluate the left operand (to get the target lvalue).
  3. Perform the assignment.
  4. Complete the side effect of the assignment (updating the left operand).

This directly resolves the infamous i = i++ case:

int i = 5;
i = i++; // C++17: Right operand i++ returns 5, then i becomes 6. Then assign 5 to i. Final i = 5.
         // Pre-C++17: Undefined behavior (no clear sequence between read and write of i)

3. Reinforced Order for Short-Circuit Operators

While C11 already guaranteed left-to-right evaluation for a && b, a || b, and a ? b : c, C17 explicitly clarifies that all side effects of the left operand are completed before evaluating the right operand (if needed). This removes any remaining ambiguity.

Expressions That Are Now Defined (But Still Bad Practice)

These expressions were undefined before C++17 but now have predictable behavior:

  • i = i++ (as detailed above)
  • i += i++ (e.g., if i=5, right operand returns 5, i becomes 6, then i +=5 makes i=11)
  • x << (x++) or x >> (x--)
  • a = b++ + c-- (right operands b++ and c-- are still indeterminately sequenced relative to each other, but each's side effects are completed before the assignment)

⚠️ Critical Note: Even though these expressions now have defined behavior, you should never write code like this. It’s unreadable, error-prone, and makes maintenance a nightmare. The standard didn’t legalize these to encourage their use—just to eliminate unnecessary undefined behavior for cases that might accidentally slip in.

What Still Remains Indeterminate/Undefined?

  • Function argument evaluation: foo(f(), g()) still has no defined order for f() and g() calls. If they modify shared state, the result is unpredictable (though not strictly undefined unless there's a data race).
  • Unrelated side effects in expressions like a = f(); b = g();: These are independent statements, so their side effects are indeterminately sequenced relative to each other.

内容的提问来源于stack exchange,提问作者Slava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:48:09