首页 >后端开发 >C++ >Bjarne Stroustrup 代码中的 std::string 链接中是否潜藏着未定义的行为?

Bjarne Stroustrup 代码中的 std::string 链接中是否潜藏着未定义的行为?

Susan Sarandon
Susan Sarandon原创
2024-10-23 18:14:58639浏览

Does Undefined Behavior Lurk in std::string Chaining in Bjarne Stroustrup's Code?

Bjarne Stroustrup 代码中的 std::string 链接表达式是否表现出未定义的行为?

在 Bjarne Stroustrup 的《C 编程语言》第四版中,代码片段举例说明了使用 std::string 的替换方法进行链接:

<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>

但是,此代码表现出 未指定的行为,而不是调用未定义的行为。

这种未指定行为的原因在于计算顺序,而链式函数调用的子表达式未指定计算顺序。在这种情况下,s.find 函数调用将在第一个 s.replace 调用之前或之后进行评估,从而更改结果字符串的长度并影响后续 find 调用的结果。

问题中的示例演示了这一点:当使用不同的编译器(clang、gcc)求值时,由于求值顺序不同,会得到不同的结果。

详细信息

函数参数具有未指定的求值顺序,而链接函数调用为每个函数调用引入从左到右的求值顺序,每个调用的参数仅在相对于该特定函数调用之前排序。

在示例中,这种不确定性出现在 s.find("even") 和 s.find(" don't") 相对于 s.replace(0, 4, "") 的评估中。

忽略进一步的子- 表达式分解、求值步骤的顺序及其相互依赖关系可以描述如下:

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

虽然 A 排序在 B 之前,B 又排序在 C 之前,但不存在排序关系 关于 A 的 B 和 D 之间的关系。因此,D 可以在 A 之前或之后进行评估,从而根据所选顺序产生不同的结果。

C 17 更改

C 17 标准加强了后缀表达式及其表达式列表的求值规则的顺序,为相关代码提供了明确的行为。排序如下:

  • 后缀表达式在表达式列表中的每个表达式之前排序。
  • 每个参数的初始化相对于任何参数的初始化都是不确定排序的。其他参数。

因此,在 C 17 及更高版本中,此代码将始终正确计算。

以上是Bjarne Stroustrup 代码中的 std::string 链接中是否潜藏着未定义的行为?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn