在使用std::for_each() 遍历同一个std::map的过程中向该map插入新元素,是否可能导致潜在的段错误(如果发生重新分配的话)?
因此,在我用C++11编写、用于AEC到 WebAssembly的编译器中,我有这段代码:此处代码链接:
if (!staticPropertiesInitialized) { // https://atheistforums.org/thread-63150-post-2055509.html#pid2055509
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,在对它进行遍历的同时修改容器的大小(使用一个 std::for_each 来实现)在循环过程中发生重新分配的极不可能的情形时,这段代码可能会导致段错误。但是 basicDataTypeSizes 当然是一个 std::map。std::map 本质上是一个红黑树,其节点在修改 std::map 时本不应被重新分配……还是会呢?
我用来测试这段代码的编译器没有发出任何警告。
解决方案
在遍历一个 std::map 的同时修改它,不会使迭代器失效。
具体来说,对于你使用的 operator[],它在 cppreference文档 中有说明:
没有迭代器或引用会失效。
(其他 std::map 修改方法也保证迭代器的有效性——参见例如 std::map::insert,std::map::emplace 等。)
因此就这一点来说,你的代码是有效的。
注:
正如Igor commented 所述,在当前遍历过程中并不保证新添加的元素会被访问到。但在这种情况下似乎并不重要。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。