Bjarne Stroustrup 程式碼中的 std::string 連結表達式是否表現出未定義的行為?
In Bjarne Stroustrup 的《C 程式語言》第四版,程式碼片段舉例說明了使用std::string 的替換進行連結方法:
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");
}
但是,此程式碼表現出未指定的行為而不是呼叫未定義的行為。
此未指定行為的原因在於評估順序,而評估順序未指定鍊式函數呼叫的子表達式。在這種情況下,s.find 函數呼叫在第一個 s.replace 呼叫之前或之後進行評估,改變結果字串的長度並影響後續 find 呼叫的結果。
問題中的範例示範了這一點:當由不同的編譯器(clang、gcc)評估時,由於不同的評估而獲得不同的結果order.
Details
函數參數具有未指定的求值順序,雖然連結函數呼叫為每個函數呼叫引入了從左到右的求值順序,但參數每個呼叫的順序僅在 之前相對於 該特定函數呼叫。
在範例中,這種不確定性出現在評估中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之前,但是之間沒有排序關係 B和D 相對於A。因此,D 可以在 A 之前或之後進行評估,從而根據所選順序產生不同的結果。
C 17更改
C 17 標準加強了後綴表達式及其表達式清單的求值規則的順序,為相關代碼提供了明確的行為。排序如下:
因此,在 C 17 及更高版本中,此程式碼將始終正確計算。
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3