Home > Blockchain >  Find key in std::unordered_map won't find an existing key
Find key in std::unordered_map won't find an existing key

Time:07-04

I'm trying to make a simple ResourceManager which uses an ordered_map to find how to import files using the extension :

#include <iostream>
#include <unordered_map>
#include <string>

class ResourceManager;
typedef void (*ImporterFn)(const std::string& path); 

// manage files and what's in the assets/ folder
class ResourceManager 
{
public:
    ResourceManager() {};
    ~ResourceManager() {};

    void addImporter(const char* extension, ImporterFn fn) {
        // avoid adding multiple importers for one extension
        if(importers.find(extension) != importers.end())
            return;
        // add importer
        std::cout << "Adding importer for " << extension << std::endl;
        importers.emplace(extension, fn);
    }

    void loadFile(const std::string& path) {
        std::size_t extDot = path.find_last_of(".");
        std::string ext = path.substr(extDot 1);

        auto it = importers.find(ext.c_str());
        if(it != importers.end()) {
            std::cout << "Importer found for " << ext.c_str() << std::endl;
            it->second(path);
        }
        else {
            std::cout << "No importer found for " << ext.c_str() << std::endl;
        }
    }
private:
    std::unordered_map<const char*, ImporterFn> importers{};
};

and I made a simple program to test it and it seems it can't find the key in the map...

int main()
{
    ResourceManager* rsx = new ResourceManager();
    rsx->addImporter("png", [](const std::string& path){
        std::cout << "Loading png image" << std::endl;
    });

    rsx->loadFile("assets/imagetest1.png");
    rsx->loadFile("assets/imagetest2.jpeg");

    return 0;
}

And it output (using g to build this example):

Adding importer for png
No importer found for png
No importer found for jpeg

So I don't know what I can do to fix this, I tried to list the key in the importers map and it seems to be there, do I need to specify a custom predicate or is the problem somewhere else ?

CodePudding user response:

Problem is that your container is using const char* as a key. Note that std::unorderd_map uses standard operator == for type provided as key. In case of const char * this equal operator compares only a pointers.

So only case where you will find item is when you use same pointer. Pointed contest doesn't meter.

Now when you were adding item pointer to string literal was used. When you tried get an item you used buffer of std::string created on runtime. This two pointers will never be the same.

Note that in C for handling string you should use std::string (and/or std::string_view since C 17).

So simple replacing type of key in map fixes problem:

private:
    std::unordered_map<std::string, ImporterFn> importers{};

https://godbolt.org/z/GrsWcqEdT

Extra: C 17 has introduced std::filesystem::path which will make this code simpler: https://godbolt.org/z/YxMME934h

  • Related