std::map fails to insert objects - c++

A program I'm making requires access pools of various types of resources, but only accessible to a few classes. The resource pool is also its own class. As such, I decided to use a static class for the resource pool and have others access it this way.
But I am running into a strange problem with adding resources to the pool. Each pool is represented as an std::map, and after insertion, the map still remains empty. I am guessing this has something to do with the map being inside a static class. Is this why maps don't work as intended here?
Relevant code of Resource Pool
class ResourcePool {
private:
static ResourcePool m_ResourcePool;
public:
ResourcePool();
~ResourcePool();
static ResourcePool* Instance() { return &m_ResourcePool; }
// Where textures are stored. ci_less is for case comparison of names
std::map <std::string, TextureResource, ci_less> Textures;
TextureResource* getTexture(std::string handle);
};
Relevant code of how it's used
Scene::Scene() {
Assets = ResourcePool::Instance();
}
TextureResource* Scene::add(std::string handle, TextureResource Texture) {
// Insertion fails
Assets->Textures.insert(std::make_pair(handle + "_tex", Texture));
// I use this line to debug, the map still shows up empty
unsigned size = Assets->Textures.size();
// look up that texture by its name
return Assets->getTexture(handle);
}
The result is, add returns NULL since nothing is found. This program doesn't crash since I'm not doing anything with the texture, just testing out the insertion for now.

Since the question doesn't contain a proper compilable program, I have created one:
#include <string>
#include <map>
#include <iostream>
class ResourcePool {
private:
static ResourcePool m_ResourcePool;
public:
static ResourcePool* Instance() { return &m_ResourcePool; }
std::map <std::string, std::string> Textures;
std::string getTexture(std::string handle) { return Textures[handle]; }
};
ResourcePool ResourcePool::m_ResourcePool;
int main()
{
ResourcePool* Assets = ResourcePool::Instance();
Assets->Textures.insert(std::make_pair("test_tex", "texture"));
std::cout << Assets->Textures.size() << std::endl;
std::cout << Assets->getTexture("test_tex") << std::endl;
return 0;
}
This works on my machine as expected using linux, g++ Debian 4.3.2-1.1.
I wonder if it works for the original poster.

Related

trying to insert a vector to an unordered_map but get "message : see reference to class template instantiation"

I'm trying to make an ecs and this is my code
#include "pandaFramework.h"
#include "pandaSystem.h"
#include <unordered_map>
#include <vector>
#include <memory>
#include <iostream>
struct Component {
NodePath* node_path;
Component(NodePath* path) {
node_path = path;
}
void start(){}
void update(){}
};
struct Spinner : Component {
void update() {
std::cout << "Hello World!\n";
}
};
class Scene : public NodePathCollection {
public:
std::unordered_map<NodePath*, std::vector<std::unique_ptr<Component>>> components;
void add_path(NodePath node_path) {
NodePathCollection::add_path(node_path);
std::vector<std::unique_ptr<Component>> empty;
components[&node_path] = std::move(empty);
}
template<typename ComponentType>
void add_component(NodePath* node_path) {
components[node_path].push_back(std::make_unique<ComponentType>(node_path));
}
};
int main(int argc, char* argv[]) {
// Load the window and set its title.
PandaFramework framework;
framework.open_framework(argc, argv);
framework.set_window_title("My Panda3D Window");
WindowFramework* window = framework.open_window();
// Load the environment model.
NodePath scene = window->load_model(framework.get_models(), "models/environment");
Scene s;
s.add_path(scene);
s.add_component<Spinner>(&scene);
// Reparent the model to render.
scene.reparent_to(window->get_render());
// Apply scale and position transforms to the model.
scene.set_scale(0.25f, 0.25f, 0.25f);
scene.set_pos(-8, 42, 0);
// Run the engine.
framework.main_loop();
// Shut down the engine when done.
framework.close_framework();
return 0;
}
And when I use add_object I get
"message : see reference to class template instantiation 'std::vectorstd::unique_ptr<Component,std::default_delete<Component>,std::allocatorstd::unique_ptr<Component,std::default_delete<Component>>>' being compiled"
What should I do?
There are multiple fundamental bugs with the shown code.
You will get the same compilation error with the following code, as well:
std::vector<std::unique_ptr<Component>> empty;
std::vector<std::unique_ptr<Component>> empty2=empty;
A std::unique_ptr, by definition, a one and only pointer to the same underlying object. There are no others. For that reason is why std::unique_ptr does not have a copy constuctor. A std::unique_ptr cannot be copied. This is an absolute rule. No exceptions. The above code attempts to copy a vector of std::unique_ptrs. Since they cannot be copied, this fails. The fact that, in this instance, the vectors are empty is immaterial.
void add_object(Object object) {
std::vector<std::unique_ptr<Component>> empty;
components[&object] = empty;
}
The assignment operator effectively attempts to make a copy of the vector, and this fails for the same reason.
It's possible to make this work using move semantics:
components[&object] = std::move(empty);
This will now compile. But now you have a different bug to deal with.
object is a parameter to this function.
When this function returns, all of its parameters get destroyed. They will no longer exist. They will cease to exist. They will become no more. They will be come ex-objects.
And the code above will be left with a pointer to a destroyed object in the unordered map. Whatever happens to touch that pointer, from that point on, by definition, will be undefined behavior. You will need to fix this as well.
The problem is very layered, as mentioned in Sam's answer. One problem is that you lack a proper copy constructor for the Component class. This can be solved by not using a temporary variable as shown in the code below:
class Scene {
public:
std::unordered_map<Object*, std::vector<std::unique_ptr<Component>>> components;
void add_object(Object object) {
// std::vector<std::unique_ptr<Component>> empty;
// Adding an empty container at the given key
components[&object] = std::vector<std::unique_ptr<Component>>();
}
};
For the other problems Sam's mentions in his answers, perhaps, instead of using a pointer to an Object, you could use the object instead. This could also lead to the same copy constructor issue, but the code should work with minimal changes.

Pointer to a vector doesn't point

I have simplified the code as much as possible.
So I have two class:
class EntityManager
{
public:
std::shared_ptr<std::vector<Entity> > getEntities()
{
return std::make_shared<std::vector<Entity> >(m_entities);
}
private:
std::vector<Entity> m_entities{};
};
and
class System
{
public:
void loadEntities(std::shared_ptr<std::vector<Entity> > entities)
{
m_entities = entities;
}
private:
std::shared_ptr<std::vector<Entity> > m_entities;
};
Now basically I want the m_entities of System to point to the m_entities of EntityManager.
I did this:
system = System();
system.loadEntities(m_entityManager.getEntities());
But then I pushed back an element into the m_entities vector of EntityManager and this element wasn't added in the m_entities vector of System, which means my pointer doesn't point.
Where is my mistake?
Thanks!
Your problem is this line: return std::make_shared<std::vector<Entity> >(m_entities);
What is happening is that the shared_ptr manages a new std::vectory<Entity> container which is initialized as a copy of m_entities. Therefore, modifying the instance in the shared_ptr doesn't modify the data member in the EntityManager class and of course the shared_ptr won't see changes made to EntityManager::m_entities.
std::make_shared doesn't "make this thing shared"; it "makes a thing that will be shared".
So, you can't just make a shared pointer out of nowhere that points to something that already exists.
Your code dynamically allocates a std::vector, copy constructed from m_entities and managed by a std::shared_ptr. It's shorthand for this:
std::vector<Entity>* ptr_to_copy = new std::vector<Entity>(m_entities);
return std::shared_ptr(ptr_to_copy);
It's not clear what you're trying to do, from the code that (by your own admission) does not achieve that goal. But it seems unlikely that std::shared_ptr is appropriate here.
If it is, then make the vector dynamically-allocated and shared from the start; otherwise, just return a reference to the vector as it is.
Hack example of a pointer-free solution.
#include <string>
#include <iostream>
#include <vector>
//Hack-sample Entity class
class Entity
{
public:
Entity(const char * name): m_name(name)
{
}
void print() // this is stupid in real life. Prefer a << overload
{
std::cout << "Hi! I'm " << m_name << "!\n";
}
private:
std::string m_name;
};
class EntityManager
{
private:
std::vector<Entity> m_entities;
public:
// hide the fact that a vector is being used to store the entities.
// you can now swap out the vector for most standard containers without
// changing any code other than the using and the declaration of m_entities
using iterator = std::vector<Entity>::iterator;
EntityManager(): m_entities({"bob", "bill"})
// just pre-loading a few test entities
{
// RAII says you should load the entities from their source here
}
// get the first entity.
iterator begin()
{
return m_entities.begin();
}
// get the end of the entity list
iterator end()
{
return m_entities.end();
}
// adds an entity
void addEntity(const Entity & entity)
{
m_entities.push_back(entity);
}
// removes an entity
iterator removeEntity(iterator rem)
{
return m_entities.erase(rem);
}
};
class System
{
public:
// example method to show System working with EntityManager by printing all of the Entities
void printEntities()
{
for (EntityManager::iterator it = m_entityManager.begin();
it != m_entityManager.end();
++it)
{
it->print();
}
}
// example method to show System working with EntityManager by adding Entities
void addMoreEntities()
{
m_entityManager.addEntity(Entity("Ted \"Theodore\" Logan"));
m_entityManager.addEntity(Entity("Excellent!!!"));
}
private:
EntityManager m_entityManager ;
};
// sample test
int main()
{
System test;
test.printEntities();
test.addMoreEntities();
test.printEntities();
}
THIS HAS BEEN A HACK. THIS HAS ONLY BEEN A HACK.
If you want to do EntityManager right, see Writing your own STL Container for hints. If you want all of the bells and whistles, the job is fairly complicated. Depending on how you are using EntityManager and the complexity of the Entity management logic, you may be better off discarding EntityManager and just using the plain, old std::vector.
Addendum: What is meant by Resource Acquisition is Initialization (RAII)?

I am trying to make a hashmap of of string functions

I am trying to make a map which stores a string as an identifier and a function that returns a string i have tried typedef but i kept running into problems because i couldn't convert my typedef string (command)() to a regular string i have also tried map commands but it gives me an expression expected error but it does work if i replace string with int. Does anybody know a way of doing this? This is what my code looks like
#include "iostream"
#include <map>
#include <functional>
using namespace std;
class GameController {
public:
void inputReader();
private:
bool gameOver = false;
map<string,string(*)()> commands;//Does not work
//commands
string commandReader(string* inputCommand);
void initCommands();
//both
char* end();
string run();
//while attacking
string attack();
string usePotion();
string useItem();
//while in room
string engage();
string searchRoom();
string rest();
string checkBag();
string checkMap();
string checkStats();
//string save();
};
#endif //ROGUE_GAMECONTROLLER_H
#include "GameController.h"
GameController::GameController(){
initCommands();
}
void GameController::inputReader() {
while (!gameOver){
string x;
getline(cin,x);
cout << commandReader(&x) << endl;
}
}
string GameController::commandReader(string *inputCommand) {
for (map<string,string>::iterator it = commands.begin(); it!=commands.end(); ++it)
{
if(it->first == *inputCommand)
{
return it->second;
}
}
return "Computer says no type help for commands";
}
void GameController::initCommands() {
commands["end"] = end;
//while attacking
commands["run"] = run;
commands["attack"] = attack;
commands["use potion"] = usePotion;
commands["use item"] = useItem;
//while in room
commands["engage"] = engage;//TODO
commands["search"] = searchRoom;
commands["rest"] = rest;
commands["check bag"] = checkBag;
commands["map"] = checkMap;
commands["stats"] = checkStats;
}
This question is tagged C++11, so here's a concise example which uses unordered_map (a real hash map, unlike std::map which my STL reference says is commonly implemented using binary search trees), and std::function.
#include <iostream>
#include <functional>
#include <string>
#include <unordered_map>
std::string foo()
{
return "foo!";
}
struct MyClass
{
static std::string bar()
{ return "bar!"; }
std::string FizzBuzz() const
{ return "FizzBuzz!"; }
std::string operator()() const
{ return "Myclass!"; }
};
int main(int argc, char **argv)
{
MyClass mc;
std::unordered_map<std::string, std::function<std::string()>> commands;
commands["myfoo"] = foo;
commands["mybar"] = MyClass::bar;
commands["myfb"] = std::bind(&MyClass::FizzBuzz, mc);
commands["myclass"] = mc;
for( const auto &f : commands)
std::cout << f.second() << std::endl;
std::cout << commands["myfoo"]() << std::endl;
return 0;
}
Pointers to member functions is not like pointers to free functions or even static methods. For one thing all member functions have a hidden this pointer in the function parameters that makes all of this object magic work.
Going through step by step:
First, define a helper:
typedef string (GameController::*funcp)();
This defines type funcp which represents a pointer to a member function of GameController (to partly take care of the this problem) that takes no parameters and returns string
Then, modify your map to use funcp
map<string, funcp> commands;
Then you have to change the assignment of the member functions a bit to be brutally explicit that it is a pointer and a member of GameController
commands["end"] = &GameController::end;
You can also save yourself some runtime trouble and use an initializer list here rather than a function and a map in every single GameController object. That'll take a bit of extra explaining and I have to be on the move in a few minutes. Sorry about that. A static map with static initializing really is better and worth your time researching, though.
The next bit I stole from the C++ Super FAQ. Read this link. Worth reading all of it, because it heads off a lot of the question you will have.
#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
This makes calling the function awesomely easy.
return CALL_MEMBER_FN(*this, it->second)();
And that should about do it for you.
edit:
Tweej demonstrates the generally better way to do this, std::function and std::bind, in their answer. Since I'm advocating the ancient ways, I'd like to explain why.
Two reasons: one is tunnel vision directly answering OP's question.
The second is With the ancient ways I could easily make commands static and save having to create a new copy of commands for every instance of GameController. When using std::bind, you have to have the bound object, and that ruins the static idea.
Poking around at the idea of just using std::function seems to have born fruit and rendered obsolete the ancient ways. gone is the CALL_MEMBER_FN macro. Gone is the funcp typedef
The map is now defined as static, what I was aiming for the the old-pre C++11 approach. Note the funcp typedef is replaced by a function that takes a pointer to GameController to supply this.
static map<string, std::function<string(GameController*)>> commands;
And the map is now rigged to use a static initializer list. No function required. This initializer needs to sit outside the class definition because... I'm not sure why. I think this is changed in C++14.
map<string, std::function<string(GameController*)>> GameController::commands
{
{"end", &GameController::end},
{"run", &GameController::run},
{"attack", &GameController::attack},
{"use potion", &GameController::usePotion},
{"use item", &GameController::useItem},
{"engage", &GameController::engage},
{"search", &GameController::searchRoom},
{"rest", &GameController::rest},
{"check bag", &GameController::checkBag},
{"map", &GameController::checkMap},
{"stats", &GameController::checkStats}
};
The map is initialized once and only once. All GameControllers will use the same commands, so the constructor is really dumb
GameController::GameController()
{
// init function is gone
}
Command reader gets a big rip-up, mostly because the point of a map is you can search it by the key. So I search for the key rather than iterating. The function call is now obvious and dead simple:
string GameController::commandReader(const string &inputCommand)
{
map<string, std::function<string(GameController*)>>::iterator found = commands.find(inputCommand);
if (found != commands.end())
{
return found->second(this);
}
return "Computer says no type help for commands";
}

unordered_map of shared_ptrs breaks C++ program

I use an unordered_map in my current C++ project and have the following problem:
When I insert a pair of objects into the unordered_map, the programm breaks and Windows shows me it's "[...].exe has stopped working", without giving me any information on the console (cmd). Some example code:
#include <unordered_map>
#include <network/server/NetPlayer.h>
#include <gamemodel/Player.h>
int main(int argc, char **argv) {
NetGame game;
boost::asio::io_service io_service;
NetPlayerPtr net(new NetPlayer(io_service, game));
PlayerPtr player(new Player);
std::unordered_map<PlayerPtr, NetPlayerPtr> player_map;
// Here it breaks:
player_map[player] = net;
return 0;
}
What I already tried:
I tried wrapping the line with a try-catch, but without success.
Details about the code:
NetPlayerPtr and PlayerPtr are boost::shared_ptr objects, the former contains some boost::asio objects like io_service and socket, the latter contains several custom objects.
I'm compiling with MinGW gcc with C++11 enabled on a 64bit Windows.
If more details are needed, please ask.
Okay, let's look at the code you linked to:
namespace std
{
template<>
class hash<Player>
{
public:
size_t operator()(const Player &p) const
{
// Hash using boost::uuids::uuid of Player
boost::hash<boost::uuids::uuid> hasher;
return hasher(p.id);
}
};
template<>
class hash<PlayerPtr>
{
public:
size_t operator()(const PlayerPtr &p) const
{
return hash<PlayerPtr>()(p); // infinite recursion
}
};
}
You have an inifinite recursion in your hash<PlayerPtr>::operator(). What you probably want is:
return hash<Player>()(*p);
or:
return hash<Player*>()(p->get());
depending on whether you want to identify the player by its internal id or its address.

Is a default value of nullptr in a map of pointers defined behaviour?

The following code seems to always follow the true branch.
#include <map>
#include <iostream>
class TestClass {
// implementation
}
int main() {
std::map<int, TestClass*> TestMap;
if (TestMap[203] == nullptr) {
std::cout << "true";
} else {
std::cout << "false";
}
return 0;
}
Is it defined behaviour for an uninitialized pointer to point at nullptr, or an artifact of my compiler?
If not, how can I ensure portability of the following code? Currently, I'm using similar logic to return the correct singleton instance for a log file:
#include <string>
#include <map>
class Log {
public:
static Log* get_instance(std::string path);
protected:
Log(std::string path) : path(path), log(path) {};
std::string path;
std::ostream log;
private:
static std::map<std::string, Log*> instances;
};
std::map<std::string, Log*> Log::instances = std::map<std::string, Log*>();
Log* Log::get_instance(std::string path) {
if (instances[path] == nullptr) {
instances[path] = new Log(path);
}
return instances[path];
}
One solution would be to use something similar to this where you use a special function provide a default value when checking a map. However, my understanding is that this would cause the complexity of the lookup to be O(n) instead of O(1). This isn't too much of an issue in my scenario (there would only ever be a handful of logs), but a better solution would be somehow to force pointers of type Log* to reference nullptr by default thus making the lookup check O(1) and portable at the same time. Is this possible and if so, how would I do it?
The map always value-initializes its members (in situations where they are not copy-initialized, of course), and value-initialization for builtin types means zero-initialization, therefore it is indeed defined behaviour. This is especially true for the value part of new keys generated when accessing elements with operator[] which didn't exist before calling that.
Note however that an uninizialized pointer is not necessarily a null pointer; indeed, just reading its value already invokes undefined behaviour (and might case a segmentation fault on certain platforms under certain circumstances). The point is that pointers in maps are not uninitialized. So if you write for example
void foo()
{
TestClass* p;
// ...
}
p will not be initialized to nullptr.
Note however that you might want to check for presence instead, to avoid accumulating unnecessary entries. You'd check for presence using the find member function:
map<int, TestClass*>::iterator it = TestMap.find(203);
if (it == map.end())
{
// there's no such element in the map
}
else
{
TestClass* p = it->second;
// ...
}
Yes, that's defined behaviour. If an element isn't yet in a map when you access it via operator[], it gets default constructed.