1

I am writing a cache for a game for school. The idea is that this cache stores Meshes, Materials, etc. and uses the location on the drive as a key so they only have to be loaded once and after that can be retrieved from the cache through the same command as they are inserted with. The problem I am running into seems to be that I cannot add items to the cache anywhere except for in the constructor. The relevant code is as follows:

#include <map>
#include "mge/materials/AbstractMaterial.hpp"
#include <string>

class Resources
{
public:
    ~Resources();
    static Resources* GetInstance();
    AbstractMaterial* GetMaterial(std::string location) const;
    Mesh* GetMesh(std::string location) const;

private:
    Resources();
    static Resources* _instance;
    std::map<std::string, AbstractMaterial*>    _materialCache;
    std::map<std::string, Mesh*>                _meshCache;
};

relevant method for loading meshes (almost identical for Materials):

Mesh* Resources::GetMesh(std::string location) const
{
    Mesh* foundMesh = _meshCache.find(location)->second;
    if (foundMesh == nullptr)
    {
        std::cout << "The requested mesh was not stored in the cache yet!" << std::endl;
        foundMesh = Mesh::load(config::MGE_MODEL_PATH + location);
        if (foundMesh == nullptr)
        {
            std::cout << "The requested mesh was not found on the disk either!" << std::endl;
            return nullptr;
        }
        else
        {
            //_meshCache[location] = foundMesh; //not working
            //_meshCache.insert(std::pair<std::string, Mesh* >(location, foundMesh)); //
        }
    }
    else
    {
        std::cout << "The requested mesh was found in the cache!" << std::endl;
    }
    return foundMesh;
}

Neither versions of the insertion into the map seem to work, they both give rather strange errors before even compiling:

The first variant (map[key] = value) gives these errors:

"no operator "[]" matches these operands"

and

"binary '[': no operator found which takes a left-hand operand of type 'const std::map<std::string,AbstractMaterial *,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' (or there is no acceptable conversion)"

And the second variant (map.insert(Key, Value)) gives these errors:

"no instance of overloaded function "std::map<_Kty, _Ty, _Pr, _Alloc>::insert [with _Kty=std::string, _Ty=Mesh *, _Pr=std::less<std::string>, _Alloc=std::allocator<std::pair<const std::string, Mesh *>>]" matches the argument list and object (the object has type qualifiers that prevent a match)"

and

"'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::insert': 6 overloads have no legal conversion for 'this' pointer"

I do not understand any of these errors since they are rather vague in my opinion, nor does what I do get from them, explain why this code does work in the constructor but not in the GetMaterial and GetMesh methods.

I would like to use this system for easy/fast assset loading, so help would be greatly appreciated.

2
  • GetMesh(std::string location) const: You cannot modify a member variable in a const member function Commented Mar 13, 2017 at 18:42
  • Your method GetMesh is marked const. As such, the method has a const this pointer and you cannot modify member variables (this is what const is all about here). Solution: either remove the const or mark your member variables (*Cache) as mutable. Commented Mar 13, 2017 at 18:42

2 Answers 2

2

The problem is that you've declared GetMesh(std::string location) const

You cannot modify a member variable in a const member function.

However, you're essentially implementing a lazy-loading pattern. From the user's perspective, their object is not changing, so you really do want to modify your cache! (It's logically const, but not physically so)

Declare them as mutable:

mutable std::map<std::string, AbstractMaterial*>    _materialCache;
mutable std::map<std::string, Mesh*>                _meshCache;

EDIT: If you're accessing your class in a multi-threaded context, you should synchronize a mutable variable just like you'd synchronize any non-const variable. Check out this other StackOverflow discussion about it

Sign up to request clarification or add additional context in comments.

2 Comments

I would add a big scary warning about the consequences this has on thread safety, especially if some unsuspecting teammate ends up using this class as a client.
@gd1: Fair enough
2

You can't use operator[] on a const std::map since it might try to insert a new element. You also can't insert into a const std::map for obvious reasons. Your method is const so _meshCache, a member of this, is treated const. Perhaps you want to make _meshCache mutable? Beware that using mutable has implications regarding concurrency.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.