Question

What would be the elegant and simple way (if exists) to implement a storage of generic objects (all other objects inherit from base). Once the object is stored, use a string handle to retrieve object or copy into another.

class Object{
    public:
        Object(){};
        ~Object(){};
};

class ObjectHandler{
    public:
        ObjectHandler(){};
        ~ObjectHandler(){};
        void InsertObject(std::string handle, std::shared_ptr<Object> obj){
            // some things happen before inserting
            _obj.insert(std::make_pair(handle,obj));
        }
        std::shared_ptr<Object> RetrieveObject(std::string handle){
            // some things happen before retrieving
            return _obj[handle];
        }
    private:
        std::map<std::string,std::shared_ptr<Object>> _obj;

}

For example, user defined classes are

class Dog : public Object{
    public:
        Dog(){};
        Dog(std::string name){dogName=name};
        ~Dog(){};
        std::string dogName;
        //...
}

class Cat : public Object{
    public:
        Cat(){};
        Cat(std::string name){catName=name};
        ~Cat(){};
        std::string catName;
        //...
}

And the following code is executed

void main(){
    ObjectHandler oh;
    Cat c("kitten"), cc;
    Dog d("doggy"), dd;

    oh.InsertObject("cat#1",c);
    oh.InsertObject("dog#1",d);

    cc = oh.RetrieveObject("cat#1");
    dd = oh.RetrieveObject("dog#1");

    std::cout << cc.catName << std::endl; // expect to print 'kitten'
    std::cout << dd.dogName << std::endl; // expect to print 'doggy'
}

I believe there should be some well established idea (pattern) to make this working right.

I also suspect std::shared_ptr might be useful here.

Thanks,

Was it helpful?

Solution

I would exercise caution here, in your example you're storing your objects as Object strictly (on the stack), since that would only allocate enough space for something of type Object, should you insert something that inherits from the type, it would have the part that describes the subclass sliced.

Good examples of the problem at hand:

One way to get around the problem is to handle pointers to the objects in your ObjectHandler instead, the objects themselves allocted on the heap.

If I'm just misinterpreting your post, then I apologise.

But if you as you said, will store smart pointers to the object instead, making a pair should look something like this:

std::map<std::string,std::shared_ptr<Object>> _obj;;
std::string handle = "hello"; //Or whatever the actual handle is.
std::shared_ptr<Object> keyvalue(new Object());

objects[handle] = std::shared_ptr<Object>(keyvalue); //alternative to std::make_pair
objects.insert(std::make_pair(handle, std::shared_ptr<Object>(keyvalue))); //this also works

Depending on at what point you want to start handling objects with smart pointers, insertion might look like:

    void InsertObject(std::string handle, Object* obj){
        _obj.insert(std::make_pair(handle,std::shared_ptr<Object>(obj)));
    }

    std::string key("hi");
    InsertObject(key, new Object());

or alternatively just:

    void InsertObject(std::string handle, std::shared_ptr<Object> obj){
        _obj.insert(std::make_pair(handle, obj));
    }

Also note that std::map's indexing operator[] overwrites the old value if it exists, while the insert you're already using will only insert if the old one doesn't exist.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top