首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ forward_list 迭代器失效:end() 解引用導致崩潰

     編輯:程式設計綜合問答

錯誤程式碼

void func(forward_list& lst, string s1, string s2) {
    auto current = lst.begin();
    auto prev = lst.before_begin();
    while (*current != s1 && current != lst.end()) // 錯誤:current 可能為 end()
        prev = current++;
    if (current != lst.end())
        lst.insert_after(current, s2);
    else
        lst.insert_after(prev, s2);
}

崩潰原因

`while` 條件**左至右求值**:先評估 `*current != s1`,再評估 `current != lst.end()`。當 `current == lst.end()` 時,`*current` 解引用**過去末端迭代器**,導致未定義行為(通常崩潰:`forward_list iterator not dereferencable`)。

修正:調整條件順序

while (current != lst.end() && *current != s1) // 先檢查是否為 end()
    prev = current++;

利用 `&&` **短路求值**:若 `current == lst.end()` 為真,直接短路,**不再執行** `*current != s1`,避免解引用失效迭代器。

完整修正版

void func(forward_list& lst, const string& s1, const string& s2) {
    auto current = lst.begin();
    auto prev = lst.before_begin();
    
    while (current != lst.end() && *current != s1) {
        prev = current++;
    }
    
    if (current != lst.end()) {
        lst.insert_after(current, s2); // 找到 s1,在其後插入
    } else {
        lst.insert_after(prev, s2);    // 未找到,在最後插入(prev 指向最後一個元素)
    }
}

關鍵觀念

  • **迭代器失效規則**:`forward_list::insert_after` **不會**使現有迭代器失效(不同於 `vector`)。
  • **`before_begin()`**:返回指向頭節點之前的迭代器,用於在開頭插入或追蹤前驅。
  • **短路求值**:`&&`、`||` 保證左運算元先評估,若結果已定則不評估右運算元,是防禦性編程關鍵。
  • **參數傳 `const string&`**:避免不必要複製。

除錯技巧

  • 使用 AddressSanitizer (`-fsanitize=address`) 精確定位迭代器越界。
  • 在迴圈加入斷點,觀察 `current`、`prev` 變化。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved