Должен ли я манипулировать значением карты C ++ с помощью указателя или путем обновления записи? - PullRequest
2 голосов
/ 04 октября 2010

Я использую C ++ std :: map для хранения большой коллекции сущностей:

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

Я буду часто изменять сущности в моей таблице (много раз в секунду). Лучше изменить эти записи с помощью указателя или лучше сделать локальную копию, изменить ее, а затем обновить таблицу?

Например ...

Через указатель:

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

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

Посредством копирования / изменения / обновления:

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; 

Я думаю, что лучше использовать указатель, но я впервые использую карты C ++, поэтому я не до конца понимаю, как они работают.

Мое большое беспокойство вызывает то, что, если я возьму указатель на одно из значений в моей таблице, возможно ли переупорядочить карту C ++ и этот указатель больше не будет действительным? Программа является многопоточной, поэтому объекты могут быть добавлены в таблицу, в то время как другие изменяются.

Я ценю помощь!

Ответы [ 2 ]

6 голосов
/ 04 октября 2010

Вы должны думать о ссылках (&), а не указателях (*).В своем нынешнем виде ваш getEntityRecord возвращает копию значения элемента карты, поэтому изменения возвращенного значения не будут видны через карту.Если вы измените эту функцию, чтобы она возвращала ссылку, она будет делать то, что вы хотите.

classEntityRecord& getEntityRecord(structureEntityID entityID)

map::find возвращает вам iterator, поле second которого содержит ссылку на map значение члена.Вы можете использовать эту ссылку для безопасного изменения значения элемента map, не беспокоясь об изменении map, при условии, что никто не удалит эту запись .

Из документации карты для SGI STL

Карта имеет важное свойство, заключающееся в том, что вставка нового элемента в карту не делает недействительными итераторы, которые указывают на существующие элементы.Стирание элемента с карты также не делает недействительными никакие итераторы, за исключением, конечно, итераторов, которые фактически указывают на удаляемый элемент.

1 голос
/ 04 октября 2010

Что касается вашего беспокойства о том, что "если я возьму указатель на одно из значений в моей таблице, возможно ли переупорядочить карту C ++, и этот указатель больше не будет действительным?", Ответ заключается в том, что вы, вероятно, не нужно сильно беспокоиться об этом, но нужно позаботиться о них (при условии, что вы используете итераторы, а не указатели, что должно быть легко, поскольку итераторы по своей конструкции действуют как указатели).

Вот что говорит стандарт о допустимости итераторов и ссылок на объекты в ассоциативных контейнерах, таких как std::map (23.1.2 / 8 "Ассоциативные контейнеры"):

Элементы вставки не должны влиять на действительность итераторов и ссылок на контейнер, а члены стирания должны делать недействительными только итераторы и ссылки на стертые элементы.

...