ホームページ  >  記事  >  バックエンド開発  >  Stroustrup の「C プログラミング言語」第 4 版の C コード連鎖メソッド呼び出しには、明確に定義された動作がありますか?

Stroustrup の「C プログラミング言語」第 4 版の C コード連鎖メソッド呼び出しには、明確に定義された動作がありますか?

Patricia Arquette
Patricia Arquetteオリジナル
2024-10-23 17:44:02969ブラウズ

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>

ただし、Clang ではアサートが通過しても、GCC や Visual Studio などの特定のコンパイラではアサートが失敗します。

問題

このコードは、関数の引数は順序付けられていない順序で評価されるため、部分式を評価する順序が指定されていません。連鎖関数呼び出しでは、各関数呼び出しに左から右の評価順序が導入されますが、各呼び出しの引数は、それらが属するメンバー関数呼び出しの前にのみ順序付けされます。

コード内の部分式 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>
結果は、4 と 7 に関する B の評価順序に基づいて異なります。

C 17 の変更

C 17 は、このコードに明確に定義された動作を与える p0145r3 の変更を導入しました。後置式とその式リストの評価ルールの順序を強化することによって。具体的には、この変更は、関数が入力される前に式リスト内のすべての式が順序付けされることを指定します。これにより、個々の部分式の評価順序に関係なく、コードが同じ結果を生成することが保証されます。

以上がStroustrup の「C プログラミング言語」第 4 版の C コード連鎖メソッド呼び出しには、明確に定義された動作がありますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。