0

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,

Nicholas
  • 452
  • 2
  • 10

1 Answers1

1

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.

Community
  • 1
  • 1
Profan
  • 181
  • 1
  • 9
  • cool! thanks for detailed suggestion. i've ammended the first post with shared_ptr. Compiled, looks fine. the last step left is to figure out 'cc = oh.RetrieveObject("cat#1");' how to deal with returned shared_ptr and get object instance instead.. – Nicholas Feb 24 '14 at 01:29
  • You can just dereference the pointer and you'll get a direct reference to the object, shared_ptr has overloaded * operator. http://en.cppreference.com/w/cpp/memory/shared_ptr/operator* – Profan Feb 24 '14 at 01:31
  • `Object obj; Dog dd; obj = *(oh.RetrieveObject(h));` but this returns type=Object. when i want to get my dog back, compiler complains about `operator=` : `dd = *(oh.RetrieveObject(h));`. will i have slicing problem you mentioned above? – Nicholas Feb 24 '14 at 01:44
  • Yes you would, take note that also when returning something of a supertype, you wouldn't be able to access members that are unique to a subtype without a cast to the subtype. Don't forget to make your destructor virtual either, http://www.parashift.com/c++-faq/virtual-dtors.html. It's important! – Profan Feb 24 '14 at 02:00