Getting pointer to an object stored in a map


I have a template based map that is declared as follows :
class CMyMap : public CMap<CString, LPCTSTR, CMyObject, CMyObject&)
      CMyMap() {};
      ~CMyMap() {};

      CMyObject *GetValuePtrFromPos(POSITION pos);

I stored some items in it.

Now I want to iterate through the map and get a pointer to each object
stored. The pointer has to point to the object embedded in the CAssoc
structure maintained by the map, so that it stays valid until the map´s
elements are removed.

CMyMap map;
POSITION pos=map.GetStartPosition();
while (pos != NULL)
   CString strKey;
   CMyObject Obj;

   CMyObject* pObj = map.GetValuePtrFromPos(pos);
   map.GetNextAssoc(pos, strKey, Obj);

Could somebody give me some hints of how to implement GetValuePtrFromPos
and tell me what the relation is between a POSITION type variable and an
internal CAssoc structure. Every help would be very appreciated.

Thanx in advance.
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

I doubt it's possible the way you described. Your definition: CMap<CString, LPCTSTR, CMyObject, CMyObject&) is so called values collection. I such type of collection you have no access to CmyObject address. To use pointers you need so called pointers collection defined as follows: CMap<CString, LPCTSTR, CmyObject*, const CmyObject*>. In this case you just don't need your GetValuePtrFromPos
method any more because the GetNextAssoc method will return you a pointer to object by position. But you have to take care about your map cleanup destroying existing objects when map collection is destructed. The deletion loop may be as following:

            CmyObject * pObj;
            CString  key;
            for (POSITION pos = map.GetStartPosition(); pos; )
                  map.GetNextAssoc( pos, key, pObj);
                  delete pObj;

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
I am sorry - a bug. For pointers collection should be:CMap<CString, LPCTSTR, CmyObject*, CmyObject*>
( remove the "const" modificatior )
bs161900Author Commented:
First of all I want to apologize for my late respons and
secondly I want to thank you for your effort in trying to
help me.

You are right saying that using a pointer collection would
be far more easy to solve my problem.
When I first began writing my application, I used object
pointers instead of objects, but I encountered some problems
when I had to compare the contents of those objects. (Using
pointers requires that you overwrite the global template function
CompareElements). Now that I am a little more familiar with the
template collections, I am considering using pointers again.

Still my question remains. Suppose I am storing bare objects
in a CMap derived collection class.
Internally, they are embedded in a CAssoc structure the framework
dynamically created. So they have an address.
I tried to implement GetValuePtrFromPos this way :

CMyObject* CMyMap::GetValuePtrFromPos(POSITION pos)
   return &(((CAssoc *) pos)->value);

But this did not work. Why ??
As for your GetValuePtrFromPos I think the following implementation would work:

CMyObject* CMyMap::GetValuePtrFromPos(POSITION pos)
      CAssoc* pAssocRet = (CAssoc*)pos;
      ASSERT(pAssocRet != NULL);
      if (pAssocRet == (CAssoc*) BEFORE_START_POSITION)
            // find the first association
            for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
                  if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
            ASSERT(pAssocRet != NULL);  // must find something
      return &(pAssocRet->value);

BUT the BEFORE_START_POSITION constant here just corresponds to the FIRST value that may be different with time. Other positions just represent some addresses which also may be filled with different CMyObject objects re-associated with the KEY. In addition there are several CMap's internal implementation details used here and they may be ( not likely ) changed in later MFC versions.

As for me the pointers approach just looks more transparent.
bs161900Author Commented:
Your routine seems to work fine. It gives me a better insight in the
workings of a map.
Although I changed my map implementation so that it holds object pointers
now, and all works fine as well. Thanks for your help.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.