ホームページ >バックエンド開発 >C++ >未定義の動作は Bjarne Stroustrup のコードの std::string 連鎖に潜んでいますか?

未定義の動作は Bjarne Stroustrup のコードの std::string 連鎖に潜んでいますか?

Susan Sarandon
Susan Sarandonオリジナル
2024-10-23 18:14:58631ブラウズ

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

Bjarne Stroustrup のコードの std::string の連鎖式は未定義の動作を示しますか?

Bjarne Stroustrup の『The C Programming Language』第 4 版、コード スニペットは、std::string の replace メソッドを使用した連鎖を例示しています:

<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.replace(0, 4, "") に関する s.find("even") と s.find(" don't") の評価で発生します。

それ以降の sub は無視します-式の内訳、評価ステップのシーケンス、およびそれらの相互依存性は次のように表すことができます:

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 標準は、後置式とその式リストの評価ルールの順序を強化し、問題のコードに明確に指定された動作を与えます。シーケンスは次のとおりです。

  • postfix-expression は、expression-list 内の各式の前にシーケンスされます。
  • 各パラメータの初期化は、任意のパラメータの初期化に関して不定にシーケンスされます。他のパラメータ。

したがって、C 17 以降では、このコードは常に正しく評価されます。

以上が未定義の動作は Bjarne Stroustrup のコードの std::string 連鎖に潜んでいますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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