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中文網其他相關文章!