首页  >  文章  >  后端开发  >  Stroustrup 的《C 编程语言》第四版中的 C 代码链接方法调用是否具有明确定义的行为?

Stroustrup 的《C 编程语言》第四版中的 C 代码链接方法调用是否具有明确定义的行为?

Patricia Arquette
Patricia Arquette原创
2024-10-23 17:44:02966浏览

Does the C   Code Chaining Method Calls in Stroustrup's

《C 编程语言》第 4 版第 36.3.6 节中的这段代码是否具有明确定义的行为?

相关代码演示了链接方法调用:

<code class="cpp">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>

但是,断言在某些编译器(如 GCC 和 Visual Studio)中失败,而它在 Clang 中传递。

问题

由于以下原因,此代码表现出未指定的行为计算子表达式的未指定顺序,因为函数参数以无序的顺序计算。链式函数调用为每个函数调用引入从左到右的计算顺序,但每个调用的参数仅在它们所属的成员函数调用之前排序。

在代码中,子表达式 s .find("even") 和 s.find(" don't") 相对于 s.replace(0, 4, "") 的顺序不确定。根据评估顺序,结果可能会因潜在的副作用而有所不同。

未指定的评估顺序

代码可以细分如下:

s.replace(0, 4, "" )                  // A
    .replace( s.find( "even" ), 4, "only" )    // B
        .replace( s.find( " don't" ), 6, "" );   // C

A 在 B 之前排序,而 B 在 C 之前排序。项目 1-9 彼此之间的排序是不确定的,但以下关系除外:

  • 1-3 在 B
  • 4-6 在 C 之前排序
  • 7-9 在 D 之前排序
但是,4-9 相对于 B 来说是不确定排序的。这种评估选择B 的 4 和 7 的顺序解释了 Clang 和 GCC 之间的不同结果。

测试评估顺序

可以使用测试程序来演示评估顺序:

<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 in complete expression: "
        << pos << std::endl ;

    return pos ;
}

int main()
{
   std::string s = "but I have heard it works even if you don't believe in it" ;
   std::string copy_s = s ;

   std::cout << "position of even before s.replace(0, 4, \"\" ): " 
         << s.find( "even" ) << std::endl ;
   std::cout << "position of  don't before s.replace(0, 4, \"\" ): " 
         << s.find( " don't" ) << std::endl << std::endl;

   copy_s.replace(0, 4, "" ) ;

   std::cout << "position of even after s.replace(0, 4, \"\" ): " 
         << copy_s.find( "even" ) << std::endl ;
   std::cout << "position of  don't after s.replace(0, 4, \"\" ): "
         << copy_s.find( " don't" ) << std::endl << std::endl;

   s.replace(0, 4, "" ).replace( my_find( s, "even" ) , 4, "only" )
        .replace( my_find( s, " don't" ), 6, "" );

   std::cout << "Result: " << s << std::endl ;
}</code>
结果根据 B 对 4 和 7 的评估顺序而有所不同。

C 17 更改

C 17 在 p0145r3 中引入了更改,这些更改为该代码提供了明确定义的行为通过加强后缀表达式及其表达式列表的求值规则的顺序。具体来说,此更改指定在输入函数之前对表达式列表中的所有表达式进行排序。这确保了无论各个子表达式的计算顺序如何,代码都会产生相同的结果。

以上是Stroustrup 的《C 编程语言》第四版中的 C 代码链接方法调用是否具有明确定义的行为?的详细内容。更多信息请关注PHP中文网其他相关文章!

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