在 BFS 实现中,由于迭代器引用无效而发生崩溃

作者: wuxianggujun创建于 2025年4月7日更新于 2025年4月7日

描述
BFS 算法在图遍历过程中出现"异常 0x80000003"(访问权限受限)和断言失败"无法解引用结尾列表迭代器",导致程序崩溃。崩溃发生在处理队列元素和访问图结构时。
重现步骤

  1. 构建并执行提供的 BFS 实现
  2. 使用测试数据初始化图:
cpp
graph.insert({"you", {"alice", "bob", "claire"}});
... // 其他节点
  1. 从"you"节点开始搜索
  2. 程序在队列处理过程中崩溃
    错误日志
Exception 0x80000003 encountered at address 0x7ff6f69aba73
File: MSVC include\list Line: 147
Expression: cannot dereference end list iterator

根本原因分析

  1. 悬浮引用
  • 原始代码使用 T& person = search_queue.front() 后跟着 pop()
  • 删除元素后对队列数据创建了无效引用
  • 后续访问 person 导致了未定义的行为
  1. 不安全的迭代器解引用
  • 直接解引用 graph.find()->second 而不进行存在性检查
  • 如果未找到键,则有可能访问 end() 迭代器
  1. 不完整的图验证
  • 在处理好友列表时没有验证节点的存在性
  • 缺失图节点可能会发生空指针解引用
    建议的修复
cpp
// 1. 安全的队列元素访问
T person = search_queue.front(); // 使用复制而不是引用
search_queue.pop();

// 2. 在访问前验证图节点
auto start_it = graph.find(name);
if (start_it == graph.end()) {
    return false; // 处理缺失的起始节点
}

// 3. 安全处理好友列表
auto person_it = graph.find(person);
if (person_it != graph.end()) {
    for (const auto& friend_name : person_it->second) {
        search_queue.push(friend_name);
    }
}

验证
在应用这些更改后:

  • 测试案例成功找到"thom"作为芒果卖家
  • 缺失节点的压力测试不再崩溃
  • Valgrind/内存检查显示清洁报告
    严重程度: 严重(崩溃/数据损坏)
    优先级: P1(必须修复)
    受影响的版本: 所有版本,2023-04-07 之前的版本
    建议的其他改进
  1. 添加单元测试:
  • 缺失起始节点
  • 节点具有空的好友列表
  • 多个连续的卖家
  1. 实现图验证包装函数
  2. 添加缺失节点的错误日志
    环境
  • 操作系统:Windows 10/11
  • 编译器:MSVC 2022(v14.34-17.8)
  • 构建配置:调试 x64
  • STL 版本:MSVC STL 2022
    附件
  • 完整修复代码

内容来源: egonSchiele/grokking_algorithms