为何退出循环后std::multimap中的元素内容发生异常变化?
容器迭代指针悬空导致的未定义行为问题
我正在尝试在OpenGL程序中实现透明效果,以下是最小可复现示例代码:
#include <map> #include <unordered_map> #include <iostream> #include <vector> class Sprite { public: std::vector<int> m_meshes; std::pair<float, float> pos; }; int main() { std::unordered_map<int, Sprite> m_sprites = { { 0, { { 43 } } }, { 1, { { 234 } } } }; std::multimap<int, const Sprite*, std::greater<int>> translucentSprites{}; for (const std::pair<int, Sprite>& spritePair : m_sprites) { translucentSprites.insert({ spritePair.second.pos.first + spritePair.second.pos.second, &spritePair.second}); std::cout << translucentSprites.begin()->second->m_meshes.size() << ' '; } std::cout << translucentSprites.begin()->second->m_meshes.size() << '\n'; return 0; }
运行该代码后,输出结果为:
1 1 0
前两个输出值为1,但第三个值却为0而非1。我尝试使用调试器排查但未找到问题根源,请问我的代码存在什么错误?
错误根源
问题出在循环迭代时的类型不匹配导致的临时对象与悬空指针:
std::unordered_map<int, Sprite>的元素类型是std::pair<const int, Sprite>,但你在for循环中用const std::pair<int, Sprite>&去接收元素。这种类型不匹配会让编译器自动创建一个临时的std::pair<int, Sprite>对象,spritePair引用的是这个临时对象,而非m_sprites容器里的真实元素。
每次循环迭代结束后,这个临时对象就会被销毁。你插入到translucentSprites中的&spritePair.second是临时对象的地址,循环结束后这些指针全部变成了悬空指针。访问悬空指针指向的内存属于未定义行为,第三个输出的0就是这种行为的随机结果。
修复方法
将循环中的迭代类型改为const std::pair<const int, Sprite>&,或者直接用auto&让编译器自动推导正确的类型,这样就能直接引用容器内的真实元素,避免临时对象的生成:
for (const auto& spritePair : m_sprites) { translucentSprites.insert({ spritePair.second.pos.first + spritePair.second.pos.second, &spritePair.second}); std::cout << translucentSprites.begin()->second->m_meshes.size() << ' '; }
修改后运行代码,输出会变为1 1 1,符合预期。
内容的提问来源于stack exchange,提问作者Roman Leshchuk
相关产品推荐
相关产品推荐

