Does std::string's Chaining Expression in Bjarne Stroustrup's Code Exhibit Undefined Behavior?
In Bjarne Stroustrup's "The C Programming Language" 4th edition, a code snippet exemplifies chaining using std::string's replace method:
<code class="cpp">void f2() { std::string s = "but I have heard it works even if you don't believe in it"; s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, ""); assert(s == "I have heard it works only if you believe in it"); }</code>
This code, however, exhibits unspecified behavior instead of invoking undefined behavior.
The reason for this unspecified behavior lies in the order of evaluation, which is unspecified for sub-expressions of chained function calls. In this case, the s.find function calls are evaluated either before or after the first s.replace call, altering the resulting string's length and affecting the subsequent find call's result.
The example in the question demonstrates this: when evaluated by different compilers (clang, gcc), differing results are obtained due to varying evaluation orders.
Details
Function arguments have an unspecified evaluation order, and while chaining function calls introduces a left-to-right evaluation order for each function invocation, the arguments of each call are sequenced before only with respect to that particular function call.
In the example, this indeterminacy arises in the evaluation of s.find("even") and s.find(" don't") with respect to s.replace(0, 4, "").
Ignoring further sub-expression breakdowns, the sequence of evaluation steps and their interdependence can be depicted as follows:
Step 1: s.replace(0, 4, "") // A Step 2: s.find("even") // B Step 3: s.replace(B, 4, "only") // C Step 4: s.find("don't") // D Step 5: s.replace(D, 6, "") // E
While A is sequenced before B, which in turn is sequenced before C, there is no sequencing relationship between B and D with respect to A. As a result, D can be evaluated either before or after A, leading to different outcomes based on the sequence chosen.
C 17 Changes
The C 17 standard strengthens the order of evaluation rules for postfix-expressions and their expression-list, giving the code in question well-specified behavior. The sequencing is as follows:
Hence, in C 17 and later, this code will always evaluate correctly.
The above is the detailed content of Does Undefined Behavior Lurk in std::string Chaining in Bjarne Stroustrup\'s Code?. For more information, please follow other related articles on the PHP Chinese website!