std :: map, указатель на значение ключа карты, возможно ли это? - PullRequest
24 голосов
/ 05 февраля 2009
std::map<std::string, std::string> myMap;

std::map<std::string, std::string>::iterator i = m_myMap.find(some_key_string);
if(i == m_imagesMap.end())
    return NULL;

string *p = &i->first;

Последняя строка действительна? Я хочу хранить этот указатель p в другом месте, будет ли он действителен в течение всей жизни программы? Но что произойдет, если я добавлю еще несколько элементов на эту карту (с другими уникальными ключами) или удалим некоторые другие ключи, не перераспределит ли она эту строку (пару ключ-значение), чтобы p стало недействительным?

Ответы [ 4 ]

52 голосов
/ 05 февраля 2009

Раздел 23.1.2 # 8 (требования к ассоциативным контейнерам):

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

То есть да хранение указателей на элементы данных элемента карты гарантированно будет действительным, если только вы не удалите этот элемент.

19 голосов
/ 05 февраля 2009

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

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

Что вы могли бы сделать, это создать небольшой объект, такой как:

struct StringPtrInMap
{
  typedef std::map<string,string>::iterator iterator;
  StringPtrInMap(iterator i) : it(i) {}
  const string& operator*() const { return it->first; }
  const string* operator->() const { return &it->first; }
  iterator it;
}

А затем сохраните это вместо строкового указателя.

1 голос
/ 05 февраля 2009

Если вы не уверены, какие операции сделают недействительными ваши итераторы, вы можете легко найти их в справочнике . Например, для vector :: insert написано:

Это эффективно увеличивает размер вектора, что вызывает автоматическое перераспределение выделенного пространства памяти, если и только если новый размер вектора превышает текущую емкость вектора. Перераспределение в векторных контейнерах делает недействительными все ранее полученные итераторы, ссылки и указатели.

map :: insert , с другой стороны, ничего подобного не упоминает.

Как сказал Пьер, вам следует хранить итератор, а не указатель.

0 голосов
/ 06 февраля 2009

Почему вы хотите это сделать?

Вы не можете изменить значение * p, так как это const std :: string. Если вы изменили его, вы можете нарушить инварианты контейнера, изменив порядок сортировки элементов.

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

...