Установка unordered_map в качестве значения для unordered_map

Итак, я пытаюсь установить unordered_map как значение для другого unordered_map. Теперь у меня проблема, что я не могу поместить значения во вторую unordered_map. Мой код выглядит так.

  std::string postCode;
  std::string[] postCodeSource = new std::string{1111,2222,3333,4444};
  std::unordered_map<std::string,unordered_map<int,Foo*>*> data;
  int k1=1234;//can be any number
  for(int i = 0; i < 4; i++){
    postCode = postCodeSource[i]
    if(data[postCode]==NULL) {
      data[postCode]=new std::unordered_map<int,Foo*>();
    }
    data[postCode]->at(int(k1)) = new Foo(postCodeSource[i]);
  }

классы:

class Foo{
  public:
  Foo();
  Foo(std::string postCode);
  std::string firstName,Customername,postCode;
}

Foo(std::string postCode); — это простой конструктор копирования.

Теперь, когда я достигаю data[lastPlz.getString()]->at(int(k1.customer)) = new Foo(&k1);, я получаю исключение из диапазона unordered_map, что имеет смысл, поскольку в k1.customer еще нет объекта! Прежде чем я изменил код, который я создал, и заполнил указатель, выглядящий так.

std::unordered_map<int,Foo*> kdnrMap
kdnrMap[k1.customer] = new Foo(&k1);

а позже я добавил kdnrMap в данные. Это больше не будет работать так, как я предполагал, поскольку для этого метода потребуется полностью заполненный kdnrMap, прежде чем я смогу добавить его к data, что я больше не могу делать.

Поэтому я ищу помощи, чтобы заполнить kdnrMap. Я пробовал почти все, что мог придумать на данный момент.


person alovaros    schedule 19.02.2020    source источник
comment
Здесь так много кода отсутствует. минимальный воспроизводимый пример, вероятно, упростит решение этой проблемы.   -  person Yakk - Adam Nevraumont    schedule 19.02.2020
comment
Хорошо, что бы вы хотели добавить, чтобы сделать его более понятным? Это почти вся функция, с которой у меня проблемы.   -  person alovaros    schedule 19.02.2020
comment
Foo, Foo2; минимальный пример, который действительно компилируется. Мы, вероятно, могли бы подразнить вашу проблему из вашего текстового описания, но это излишне сложно и двусмысленно. Просто напишите простой код, демонстрирующий вашу проблему.   -  person Yakk - Adam Nevraumont    schedule 19.02.2020
comment
Обратите внимание, что operator[] довольно дорог, вам лучше использовать его только один раз, если в действительности нет необходимости использовать его несколько раз. Вы, поскольку ваша карта, кажется, владеете данными, вам лучше использовать интеллектуальные указатели.   -  person Slava    schedule 19.02.2020
comment
Кстати, зачем вам хранить внутреннюю карту в виде указателя? Просто чтобы сделать ваш код более сложным и подверженным ошибкам?   -  person Slava    schedule 19.02.2020
comment
PostCode такой же, как lastPlz.getString()? И как инициализируется почтовый код?   -  person SPD    schedule 19.02.2020
comment
И почему вы храните Foo во внутренней карте как указатель? Почему бы просто не std::unordered_map<std::string,std::unordered_map<int,Foo>> data;?   -  person Daniel Langr    schedule 19.02.2020
comment
Почему вы так одержимы динамическим распределением памяти? Фон Java? Вы усложняете свою жизнь больше, чем нужно, используя new везде   -  person Slava    schedule 19.02.2020
comment
@Слава, да, java немного сломал меня таким образом, и я всегда думаю, что указатели работают быстрее, чем настоящие объекты. Карта предназначена для получения, хранения и печати данных, поэтому мне нужен максимально быстрый доступ.   -  person alovaros    schedule 19.02.2020
comment
Тогда вы делаете это не только сложнее, но и немного медленнее, так как будет задействована еще одна ненужная косвенность. Угадайте, где std::unordered_map хранит свои данные?   -  person Slava    schedule 19.02.2020


Ответы (1)


Вам действительно не нужно хранить внутреннюю карту в качестве указателя. Просто позвольте внешней карте владеть внутренней, например:

std::unordered_map<std::string,
   std::unordered_map<int, std::unique_ptr<Foo>>> data;
data[postCode][int(k1.Kundennr)] = new Foo(&k1);

Я советую не использовать здесь необработанные указатели, так как существует высокий риск утечки памяти, если вы замените значение во внутренней карте. Использование std::unique_ptr значительно упрощает работу с указателями.

Ваше исключение, вероятно, возникает из-за того, что unordered_map::at требует, чтобы значение содержало ключ, который вы запрашиваете, чтобы получить ссылку на значение, которое оно отображает. Если вместо этого вы используете operator[], как в моем примере, карта создаст запись, если ключ не найден.

Если вы по-прежнему настаиваете на том, чтобы значения внешней карты были указателями на внутреннюю карту, вы можете добавить такие элементы:

std::unordered_map<int, Foo*> &inner = *data[postCode];
inner[int(k1.Kundennr)] = new Foo(&k1);

or

data[postCode]->operator[](int(k1.Kundennr)) = new Foo(&k1);
person Jorge Bellon    schedule 19.02.2020
comment
Спасибо! -›operator[] сделал именно то, что я искал. Я мог бы быть далек от этого, но я использовал внутреннюю карту в качестве указателя, потому что я думал, что это будет быстрее. Я не уверен, должен ли я использовать умные указатели, я работаю над программой, которой больше 20 лет, и у нас есть МНОГО необработанных указателей, меня учили не смешивать эти два - person alovaros; 19.02.2020
comment
Твоя мысль неверна, если повезет, то не медленнее - person Slava; 19.02.2020
comment
Если вы не можете использовать интеллектуальные указатели, имейте в виду, что data[postCode][0] = new Foo() может привести к утечке памяти, если вы не проверите, существует ли предыдущая запись для того же ключа. В общем, unordered_map существует с C++11, поэтому, если вы включаете современную функцию в старый код, вы можете сделать это правильно. - person Jorge Bellon; 19.02.2020
comment
Все данные, поступающие из почтового кода базы данных, (очевидно) не уникальны. Но второй итератор является уникальным идентификатором клиента, поэтому вероятность того, что это просто будет переопределено, очень мала или отсутствует. Все равно спасибо за совет! - person alovaros; 19.02.2020
comment
@Слава, так как мой код работает так, как задумано, завтра я собираюсь провести несколько тестов производительности и проверить, не быстрее ли использование объектов. Спасибо за ваш совет, и я действительно очень заинтересован в результатах! - person alovaros; 19.02.2020
comment
@alovaros Я сомневаюсь, что вы можете надежно проверить разницу на предмет дополнительной косвенности, в любом случае std::unordered_map сохраняет свои значения в динамически выделяемой памяти, поэтому вы ничего не выиграете, это точно. - person Slava; 19.02.2020
comment
Скорее всего, это не будет иметь большого значения. Неупорядоченные карты делают распределения при изменении размера хеш-таблицы и добавлении новых узлов в любом случае. Однако код намного проще и его легче поддерживать. - person Jorge Bellon; 19.02.2020