-2

So recently I was experimenting with some code and found an incredibly strange error. I've created an std::map for storing fonts for my program. However, through a long session of debugging, I managed to find out that this map was storing a value (NULL) with the key "arial" before I emplaced "arial" within it. So I also found that when I change the program so that it never emplaces "arial" within the map, the map still contains "arial".

Here is a basic recreation of the class hierarchy I have set up:

#include "SDL_ttf.h"
#include <map>
#include <string>
#include <array>

class AssetManager{
public:
    void addFont(std::string ID, std::string path, int fontSize){
        std::cout <<""; //if we put a breakpoint here, the first time it stops, "arial" is already defined within fonts.
        fonts.emplace(ID, TTF_OpenFont(path, fontSize);
    }
private:
std::map<std::string, TTF_Font*> fonts;
};

class Game{
public:

void init(){
    if(TTF_Init() == -1){
    std::cout << "Failed to init SDL_TTF" << std::endl; //this has never gotten called; TTF always succeeds in initializing
    }
    assets->addFont("fontname", "assets/Arial.ttf", 16);
}

static shared_ptr<AssetManager>(new AssetManager) assets;

};

main(int argc, char* argv[]){
    Game *game = nullptr;
    game = new Game;
    game->init();
}

As you can see, in this program, we never add a font called "arial", and yet for some reason (I'd assume it's something along the lines of a cache error), fonts contains data for "arial" before it was ever told, in this instance of the program, what "arial" is. In other words, "arial" was defined in the previous instance, but never in this instance, but the map still has a key for "arial". If anybody knows why or how such a thing can occur I'd love to hear it.

Cyerunix
  • 71
  • 11
  • `static shared_ptr(new AssetManager) assets;` is not a valid syntax and should not compile. – Igor Tandetnik Aug 25 '19 at 17:47
  • That program doesn't contain a string literal "arial". It doesn't emplace the key `"arial"` into the map. – Igor Tandetnik Aug 25 '19 at 17:49
  • 3
    I predict that, somewhere in the code not shown, you do `fonts["arial"]`. This has the side effect of inserting the key with default-constructed value. – Igor Tandetnik Aug 25 '19 at 17:50
  • 1
    Thanks for creating a [mcve]. But please, try that code before posting. – Thomas Weller Aug 25 '19 at 17:52
  • Apart from using [] elsewhere in the program resulting in creating the key, another possibility is simply that you are compiling with optimisation and the compiler is reordering some parts of the emplace to **before** the breakpoint. – Vorpal Aug 25 '19 at 18:36

1 Answers1

2

I'm guessing you are using std::maps operator[]. That operator will not just look up an existing entry. It will create the entry if it's not already there, with a default constructed (actually "value initialized") value.

This is actually a feature in many cases. For example it allows you to do something like the following to count occurances of characters in a string:

std::map<char, int> result;
for (const auto& c : some_string) {
    ++result[c];
}

If you just want to look up a key, without the insertion behaviour, then you have several options:

std::map::at

std::map::find

std::map::contains

And others.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70