Multiple types in a map container C++

Started by
11 comments, last by Soundstone 10 years, 11 months ago

For this kind of problem I use claw::multi_type_map :

For example :


typedef claw::meta::type_list_maker<A*, B*>::result my_type_list;
claw::multi_type_map<int, my_type_list> my_multi_map;

my_multi_map.set<0>( myA );
my_multi_map.set<1>( myB );

Then I use a visitor to explore the map.

With this solution, A and B do not need to share a common base class, nor to have any virtual stuff. There is also no dynamic_cast.

C++ developper with some 2D art skills
http://www.stuff-o-matic.com

Advertisement

I'm confused. You say it's _exactly_ 9 slots and they are _consecutively_ numbered 0-8? At which point did that make you think "map<int, ptr>" instead of "array<ptr, 9>"?

Why fill it with dummy instances and loop through all the pointers and call functions on them, instead of just checking them for 0?

And why even do that, instead of just adding a simple "numItems" variable to box that keeps track of the next free slot?


class Box
{
public:
    Box() : numItems(0) {}
 
    void addItem(shared_ptr<Item> item)
    {
         if (numItems < 9)
         {
              items[numItems++] = item;
         }
    }
 
private:
   std::array<shared_ptr<Type>, 9>;
};

Why pass a shared_ptr? Because in your code you never check if the item was successfully added. You ownership is completely unknown at this point. If you delete it at the calling site and it was added -> access violation. If you don't delete it and it wasn't added -> memory leak.

Why a shared_ptr? Without knowing the usage of that box, it is safer to allow code that is currently using an item from the box to keep it alive, just in case it gets removed from the box in between. Using a smart pointer also means there is no need to explicitly delete an object in the box before replacing it (if that is even a use case).

Your main function (as explained above) also has a big issue.


int main()
{
     Box myBox; //This has no business being a pointer in the first place
     myBox.addItem(make_shared<ItemA>("Steve", 0, "is a man", 4, 6, 7, 17, 8, 3.4f);
}

The real problem is of course trying to stuff two completely unrelated types into the same container. Why? It will just result in a huge mess of if/else and dynamic_casts or getType(). Put them in two different arrays and let the box class hide that fact. Of course if you ever want to access an item in the box, you're back to the same problem. What type should that function return?

Generally you want to hide all members and use a _common_ interface for A and B. Depending on what they are supposed to do, try to abstract that. You want them to print their data? Have a virtual function "print" in both of them (and the base class). Don't even think about placing that code outside the classes and have it rip the data from their guts.

f@dzhttp://festini.device-zero.de

Hi Trienco, Thanks for the help and the advice, what you present seems to be a good solution to go off of. I think my originial intention with the map container over the array was that I wanted to have a string key that I could easily reference the items by. The items in the container are similar and inherit from an abstract base item class. The end game was to use this as part of an inventory system for a game. Not necessarily what the player is carrying but what they are storing into an external container in game. This container has actions that it takes much like an AI player. I was really tied to the idea of item lookup through string key. Thank you all for your comments and help. I'll be thinking through this much more in depth.

This topic is closed to new replies.

Advertisement