Why are the elements of the std::multimap changing after exiting the loop in this code?

I am trying to implement a transparency in my OpenGL prorgam. Currently I have such function (minimal reproducible example):

#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;
}

After running of this code, I get the following result:

1 1 0

The first two numbers are 1, but the third number for some reason is 0, not 1. I tried to use debugger, but it did not help. What is my mistake here?

>Solution :

When const std::pair<int, Sprite>& spritePair goes out of scope (in each iteration), the copy of the Sprite will be gone and the pointer will be dangling.

You can fix it by making it

const std::pair<const int, Sprite>& spritePair

which would then reference the actual pair in the map instead of creating a std::pair<int, Sprite> via conversion.

An alternative fix is to use structured bindings:

for (const auto& [idx, sprite] : m_sprites) {
    translucentSprites.insert({sprite.pos.first + sprite.pos.second, &sprite});

A simplification could be to use emplace instead of insert:

translucentSprites.emplace(sprite.pos.first + sprite.pos.second, &sprite);

Leave a Reply