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