2010-12-29 3 views
13

У меня есть карта, как этотМожно ли получить объект в std :: map по ссылке?

map<int,object> objmap; 
object& obj = objmap.find(num)->second; 
object& obj2 = objmap[num]; 

Какие бы изменения я делаю в объекте должны быть отражены на карте. Подобная вещь не может быть выполнена в векторе, поскольку она изменяет расположение объектов, когда требуется больше места. Безопасно ли это делать на std :: map? и это целесообразно? Вторая версия дает ошибку, так как у моего объекта нет пустого конструктора. Если я объявлю, что пустой конструктор ничего не делает, две линии будут работать одинаково?

ответ

18

До тех пор, пока объект не будет удален с карты, тогда да, это безопасно. Когда вставляемые в объекты карты не перемещаются, даже если другие элементы добавлены или удалены.

object& obj = objmap.find(num)->second; 

Это потенциально опасно, если вы не уверены в том, что элемент с ключом num на самом деле существует в карте. Если вы не уверены, вы можете использовать перегрузку insert, которая возвращает iterator и bool, которая указывает, был ли вставлен новый элемент, или элемент с заданным ключом уже присутствовал на карте.

E.g.

object& obj = objmap.insert(std::make_pair(num, object(arg1, arg2, argN))).first->second; 
+1

Вы знаете, где и как найти такую ​​информацию в документах? На самом деле я даже не знал, как искать этот ответ: как правильно сказать «объекты не перемещаются»? Я думаю, что спецификации должны определять это именно потому, что это такое важное различие между вектором и картой. – Flynsee

11

Это безопасно, пока элемент не удаляется с карты.

Однако вторая линия не вполне сейф:

object& obj = objmap.find(num)->second; 

Если нет элементов с ключом num в карте, find вернется objmap.end(). Эта возможность должна быть испытано перед разыменования возвращенного итератора:

const std::map<int, object>::iterator it = objmap.find(num); 
if (it != objmap.end()) 
{ 
    object& obj = it->second; 
    /* ... */ 
} 

Теперь, если цель не реально найти но на самом деле вставить, вызывая operator[] возможность (хотя, как вы уже заметили, это требует, чтобы значение предоставило конструктор без параметров). Но вы должны понимать, что это две совершенно разные вещи:

  • findтолько находит: если ключ не найден, ничто не вставляется и end итератор возвращаемые
  • operator[]всегда возвращается ссылка на значение на карте: отсутствовал ключ, была введена вставка (для стандартного сконструированного значения: таким образом, требование конструктора)
1

Если вы хотите внести изменения в объект на карте, который будет отображаться, вы, скорее всего, захотите изменить свою карту, чтобы сохранить указатели на объекты, а не на объекты. Ссылки могут работать до тех пор, пока вы ничего не делаете с объектом между ссылкой, которая приведет к ее недействительности.

Например, следующий код будет разорвать с помощью ссылки:

object& obj = objmap.find(num)->second; 
objmap.erase(objmap.find(num)); // should check for objmap.end() - left out for simplicity 
obj.DoSomething(); // this object has been destroyed, so the reference is invalid 
4

Если ваш вопрос аннулирует ли std::map его итераторы в своих мутируют функции, то ответ отрицательный. Стандартные гарантии std::map не делают недействительными его итераторы.

0

Выполнение того, что вы делаете, является распространенным способом реализации кэширования.

Если элемент уже есть, то оператор [] возвращает элемент. Если его нет, он создаст «пустой» с конструктором по умолчанию, и вы сможете записать его для последующего использования.

Конечно, обычно используется shared_ptr как value_type, который будет иметь «пустое» значение при создании. В этом случае вам нужно получить shared_ptr по ссылке, чтобы вы могли вызвать reset() на нем.

Как и в случае с любыми коллекциями/кэшированием и т. Д., Вы должны остерегаться проблем с потоковой безопасностью, если это делается в многопоточном приложении.

Что я не уверен, что вы хотели знать, можно ли хранить ссылку где-нибудь (или указатель на нее) и ожидать, что она будет действительной позже, когда к карте будут добавлены другие элементы, и да, это будет ,

Смежные вопросы