首页 >后端开发 >C++ >STL 方法链接是否保留 C 中的求值顺序?

STL 方法链接是否保留 C 中的求值顺序?

Patricia Arquette
Patricia Arquette原创
2024-10-24 03:28:01588浏览

Does STL Method Chaining Preserve Evaluation Order in C  ?

C 中的链接 STL 方法是否保留求值顺序?

在 Bjarne Stroustrup 的《C 编程语言》第 4 版中,以下代码片段举例说明了方法链接:

<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。但是,根据所使用的编译器,此表达式的行为是不明确的:

  • Clang: 计算遵循预期顺序,导致 s 为“我听说它仅在以下情况下才有效”你相信它”。
  • GCC:求值顺序不可预测,导致 s 取不正确的值。
  • Visual Studio:与 GCC 类似,评估是不明确的,经常产生相同的错误结果。

揭示未指定的行为

由于不确定性,代码表现出未指定的行为子表达式的求值顺序,尽管不调用未定义的行为。问题的关键在于链式函数调用中函数参数的求值顺序。

具体而言,对于以下子表达式:

  • s.find("even")
  • s.find(" don't")

它们的求值顺序对于以下内容是不确定的:

  • s.replace(0, 4 , "")

这意味着可以在替换调用之前或之后评估 find 调用,从而影响 s 的长度,从而改变 find 调用的结果。

使用自定义查找函数的插图

为了演示这种歧义,代码的修改版本使用自定义 my_find 函数,该函数报告每个子表达式求值中搜索字符串的位置:

<code class="cpp">std::string::size_type my_find(std::string s, const char *cs) {
  std::string::size_type pos = s.find(cs);
  std::cout << "position " << cs << " found: " << pos << std::endl;
  return pos;
}</code>

使用不同的编译器运行此代码会根据计算顺序产生不同的结果:

  • Clang: my_find 在计算之前先计算为“even”
  • GCC: my_find 在评估“even”之前先评估“don’t”,从而导致错误的结果.

C 17 更改

C 17 标准 (p0145r3) 对表达式求值顺序规则进行了改进,以解决这种歧义。它加强了后缀表达式及其表达式列表的求值顺序,如下所示:

  • 后缀表达式在表达式列表中的每个表达式和任何默认参数之前排序。

这可确保链式方法调用按预期顺序进行计算,从而解决了 C 17 中的未定义行为。

以上是STL 方法链接是否保留 C 中的求值顺序?的详细内容。更多信息请关注PHP中文网其他相关文章!

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