Thread: store in std::map all kind of structs

  1. #1
    Registered User
    Join Date
    Mar 2008
    Posts
    58

    store in std::map all kind of structs

    Hello all and sorry for my bad english
    i have std::map that uses string as akey and i like it to hold different kinds of
    structs ( my structs define in the application )
    but how can i tell the map to hold it
    for example : std::map<std::string, ...here go's what ??... > mystructsMap;
    and say i have struct1 struct2 struct3 in my application

  2. #2
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    You can't, how would it know how much memory to allocate for an element, or even still, what would be the return type of a look-up? You'd need a new map for each value type.
    One way to avoid this is to make a struct union encompassing all of your struct types.
    Another solution is to make a map of void *'s instead.
    In both cases, ti will be up to you, the programmer, to keep track of which struct is valid in the union returned by the map or what is represented by the void * returned.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Perhaps boost::any can be used as the mapped_type here.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    You can derive all your structs from a common base struct and store pointers to the base struct in the map.
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You can derive all your structs from a common base struct and store pointers to the base struct in the map.
    There is a problem with this if you don't use typedef on the struct. One would think that merely storing a pointer to the base struct would allow you to place any struct derived from base in the container. It does with one caveat. When you try to access data in the derived struct you will get garbage. Structs suffer slicing problems and because of this if you want to store all objects of type base in a container I recommend you make the base a class instead of a struct.

    What you can do which is very close to what you want is this:

    Code:
    namespace app_ifaces
    {
    
        class IObject
        {
            public:
              virtual ~IObject() { }
              virtual void Foo()  = 0;
              virtual void Bar() = 0;
        };
    
    }
    
    namespace object_impl
    {
    
        class Object:public app_ifaces::IObject
        {
             public:
                 Object() { };
                 virtual ~Object() { }
                 virtual void Foo() { }
                 virtual void Bar() { }
    
        };
    }
    
    namespace app_mgrs
    {
    
        class ObjectMgr
        {
            typedef std::map<std::string,app_ifaces::IObject *> ObjectMap;
            typedef ObjectMap::iterator ObjectMapIter;
            typedef ObjectMap::const_iterator constObjectMapIter;
            
            public:
                 ObjectMgr();
                 virtual ~ObjectMgr();
          
                 void addObject(app_ifaces::IObject *pObject);
                 bool removeObject(std::string name);
                 app_ifaces::IObject * getObject(std::string name);
           
             private:
                ObjectMap m_Objects;
        };
    
    }
    
    namespace object_impl
    {
    
       class SpecificObject
       {
           public:
              SpecificObject() { }
              virtual ~SpecificObject() { }
    
              virtual void Foo();
              virtual void Bar();
     
              void doStuff();
              void doSomeMoreStuff();
           
           private:
              int some_variable;
        }; 
    }
    And now you could add SpecificObject(s) to ObjectMgr or you could add Object(s) to ObjectMgr. I would recommend that ObjectMgr be a singleton object so that only one instance of it can be created/used.
    Last edited by VirtualAce; 10-18-2008 at 12:46 PM.

  6. #6
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Bubba View Post
    There is a problem with this if you don't use typedef on the struct. One would think that merely storing a pointer to the base struct would allow you to place any struct derived from base in the container. It does with one caveat. When you try to access data in the derived struct you will get garbage. Structs suffer slicing problems and because of this if you want to store all objects of type base in a container I recommend you make the base a class instead of a struct.
    That sounds a bit off to me. You can't slice a pointer by storing it in the map, and so long as you have a way of telling what the real type the object points to is, then you can dynamic_cast it to that and everything will be accessible just fine. Remember that a struct and a class really only differ by whether their members are public or private by default, in C++.
    However I'd possibly avoid a dynamic_cast by implementing the visitor pattern on the derived objects.

    Other than that, perhaps a VARIANT or the boost one of those can help.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Remember that a struct and a class really only differ by whether their members are public or private by default, in C++.
    Yes this is true but we ran into this about a month ago. We had a container that had base struct pointers and then added objects that were derived from the base struct. When we went to access the data we got nothing but garbage. Switching the code to classes fixed it. All we could gather is somehow it was slicing when we added to the container. Dynamic cast did not work as expected. We never found out why and didn't really waste time on it since we knew classes worked fine. We changed it, counted it a victory, and moved on. I posted that b/c under MSVC 2003 .NET and using MS's STL impl of std::map it just did not work as expected. I did not understand what was happening since we were storing base struct pointers in the map and then adding pointers to derived struct objects to it. Should have worked but none of the derived struct members were visible.

    After the fact, it might be worth looking into across compilers and implementations of the STL. I still don't know what exactly was wrong and theoretically it should have worked.

    Code:
    #include <tchar.h>
    #include <map>
    #include <iostream>
    
    #define DO_TEST1
    #define DO_TEST2
    
    struct Base
    {
        int bx;
        int by;
        virtual void printOut()
        {
            std::cout << "Base BX: " << bx << std::endl;
            std::cout << "Base BY: " << by << std::endl;
        }
    
    };
    
    struct Derived:public Base
    {
        int dx;
        int dy;
    
        virtual void printOut()
        {
            Base::printOut();     
            std::cout << "Derived DX:" << dx << std::endl;
            std::cout << "Derived DY:" << dy << std::endl;
        }
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        std::map<unsigned int,Base *> m_Test;
        
    #ifdef DO_TEST1
        Derived x;
        x.bx = 3;
        x.by = 4;
        x.dx = 5;
        x.dy = 6;
        m_Test.insert(std::pair<unsigned int,Base *>(0,&x));
        std::map<unsigned int,Base *>::iterator iter = m_Test.find(0);
        Derived *ptrX = dynamic_cast<Derived *>(iter->second);
        ptrX->printOut();
    #endif
    
    #ifdef DO_TEST2
        Derived *dynX = new Derived();
        dynX->bx = 7;
        dynX->by = 8;
        dynX->dx = 9;
        dynX->dy = 10;
        m_Test.insert(std::pair<unsigned int,Base *>(1,dynX));
        std::map<unsigned int,Base *>::iterator iter2 = m_Test.find(1);
        Derived *ptrDynX = dynamic_cast<Derived *>(iter2->second);
        ptrDynX->printOut();
        delete ptrDynX;
    #endif
    
        int ch = getchar();
        
        return 0;
    }
    Just tested it with this code and you are right it works just fine. I wonder what happened a month ago to give us so many problems??? I knew it should have worked. Tested in MSVS 2005 .NET standard.
    Last edited by VirtualAce; 10-18-2008 at 03:38 PM.

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Youre right that does sound weird. I can certainly understand switching from one to the other if that solved the problem. I never really used VS2003 much, I pretty much went from 2002 to 2005 and then to 2008.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Structs, pointers and functions
    By osici in forum C Programming
    Replies: 2
    Last Post: 04-29-2009, 12:35 AM
  2. Structs and mem allocation
    By reversaflex in forum C Programming
    Replies: 2
    Last Post: 07-03-2008, 07:46 AM
  3. Creating array of structs
    By knirirr in forum C++ Programming
    Replies: 12
    Last Post: 06-18-2008, 08:30 AM
  4. Multidimentional structs + memcpy() == FAIL
    By Viper187 in forum C Programming
    Replies: 8
    Last Post: 06-18-2008, 02:46 AM
  5. What kind of job...
    By Discolemonade in forum A Brief History of Cprogramming.com
    Replies: 5
    Last Post: 08-15-2005, 08:23 PM