views:

59

answers:

2

I'm using a C++ std::map to hold a large collection of entities:

using std::map;  
map {structureEntityID, classEntityRecord} tableEntityRecords; //(replace {}s with arrows)

I will be frequently modifying the entities in my table (many times a second). Is it better to modify those records via a pointer or is it better to make a local copy, modify it, and then update the table?

For example...

Via a pointer:

classEntityRecord* getEntityRecord(structureEntityID entityID)  
{  
    map {structureEntityID, classEntityRecord}::iterator iteratorEntityRecord;  
    iteratorEntityRecord = tableEntityRecords.find(entityID);  
    return &iteratorEntityRecord->second;  
}  

classEntityRecord *entityRecord;  
entityRecord = getEntityRecord(entityID);  
entityRecord->x = 15;  

Via a copy/modify/update:

classEntityRecord getEntityRecord(structureEntityID entityID)  
{  
    map {structureEntityID, classEntityRecord}::iterator iteratorEntityRecord;  
    iteratorEntityRecord = tableEntityRecords.find(entityID);  
    return iteratorEntityRecord->second;  
}

classEntityRecord entityRecord;  
entityRecord = getEntityRecord(entityID);  
entityRecord.x = 15;  
tableEntityRecords[entityID] = entityRecord; 

I would think it is better to use a pointer, but this is my first time with C++ maps so I don't fully understand how they work.

My big worry is if I take a pointer to one of the values in my table, is it possible for the C++ map to be reordered and have that pointer no longer be valid? The program is multithreaded so entities can be added to the table while others are being modified.

I appreciate the help!

+3  A: 

You should be thinking of references (&) not pointers (*). As it stands your getEntityRecord returns a copy of the map element value, hence changes to the returned value will not be seen via the map. If you change this function to return a reference, it will do what you want.

classEntityRecord& getEntityRecord(structureEntityID entityID)

map::find returns you an iterator, the second field of which contains a reference to the map member value. You can use this reference to safely modify the map member value without worrying about the map being modified, provided nobody else deletes that entry.

From the map documentation for SGI STL

Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.

Steve Townsend
Great, thanks for the help. It was an easy swap in my code for your suggestion. :-)
Clint
@Clint - in general, avoid raw pointers if possible. A reference cannot crash your code because it's NULL.
Steve Townsend
A: 

As for your worry about "if I take a pointer to one of the values in my table, is it possible for the C++ map to be reordered and have that pointer no longer be valid?", the answer is that you probably don't need to worry much about it - but do need to take some care (assuming that you use iterators rather than pointers, which should be easy, since iterators act like pointers by design).

Here's what the standard says about the validity of iterators and references to objects in associative containers like std::map (23.1.2/8 "Associative containers"):

The insert members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

Michael Burr
Thanks for the help! Especially for pointing out that references will not be invalidated.
Clint