首頁  >  文章  >  後端開發  >  Bjarne Stroustrup 程式碼中的 std::string 連結中是否潛藏著未定義的行為?

Bjarne Stroustrup 程式碼中的 std::string 連結中是否潛藏著未定義的行為?

Susan Sarandon
Susan Sarandon原創
2024-10-23 18:14:58511瀏覽

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