You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

遍历std::map时用std::for_each插入新元素,是否会因重分配引发段错误?

遍历std::map时插入元素的安全性问题

我用C++11编写了一款AEC转WebAssembly编译器,其中包含以下代码:

if (!staticPropertiesInitialized) {
      basicDataTypeSizes["Integer32"] = 4;
      basicDataTypeSizes["Character"] = 1;
      basicDataTypeSizes["Decimal32"] = 4;
      basicDataTypeSizes["Integer64"] = 8;
      basicDataTypeSizes["Decimal64"] = 8;
      basicDataTypeSizes["Integer16"] = 2;
      std::for_each(basicDataTypeSizes.begin(), basicDataTypeSizes.end(),
                    [&](std::pair<std::string, int> type) {
                      if (not(isPointerType(type.first)))
                        basicDataTypeSizes[type.first + "Pointer"] =
                            4; // JavaScript (WebAssembly) virtual machine is
                               // 32-bit (pointers being 32 bits or 4 bytes
                               // long), unless somebody switches to the 64-bit
                               // mode (which is almost never done).
                    });
      basicDataTypeSizes["Nothing"] = 0;
}

显然,若basicDataTypeSizes是std::vector,这种在遍历期间修改容器大小的操作可能因内存重分配引发段错误。但这里basicDataTypeSizes是std::map,它本质是红黑树结构,修改时节点应该不会被重分配?事实是否如此?我测试过的编译器均未为此代码发出警告。


解答

  • 遍历std::map时插入新元素是完全安全的,这和std::vector的行为有本质区别:
    • std::vector采用连续内存存储,插入元素可能触发内存扩容重分配,导致所有原有迭代器失效;而std::map基于红黑树实现,每个元素都是独立的动态分配节点,插入新元素只会调整树的结构(旋转、重新着色),不会移动现有节点的内存位置,已存在的迭代器(除了被删除节点的迭代器)都会保持有效。
    • 你这段代码中,遍历过程中插入的"XXXPointer"类键值对是新增的红黑树节点,不会影响正在遍历的原有节点的迭代器,因此不会出现类似std::vector的段错误问题。
  • 编译器未发出警告是合理的:这种操作符合C++标准对std::map的行为定义,不属于未定义行为,编译器没有理由触发警告。
  • 额外注意:如果是在遍历std::map时删除元素,则需要注意迭代器失效问题(比如删除当前迭代器指向的元素时,要用erase返回的新迭代器继续遍历),但你这里仅执行插入操作,不存在这个风险。

内容的提问来源于stack exchange,提问作者FlatAssembler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 00:23:10