Замените существующие и добавьте новые записи в std :: map - PullRequest
0 голосов
/ 28 июня 2018

Рассмотрим следующий фрагмент:

MapT map;

map["A"] = 1;
map["B"] = 2;
map["C"] = 3;
map["D"] = 4;
map["E"] = 5;

MapT mapSecond;

mapSecond["A"] = 10;
mapSecond["B"] = 20;
mapSecond["C"] = 30;
mapSecond["X"] = 4;
mapSecond["Y"] = 5;

MapT::const_iterator itSecond = mapSecond.begin();
MapT::iterator it = map.begin();

for (; itSecond != mapSecond.end(); ++itSecond)
{
    std::pair<MapT::iterator, bool> pair = map.insert(std::make_pair(itSecond->first, itSecond->second));
    if (!pair.second)
    {
        pair.first->second = itSecond->second;
    }
}

for (; it != map.end(); ++it)
{
    std::cout << it->first << " " << it->second << std::endl;
}

Я предполагаю, что использование возвращенного итератора из insert является наиболее эффективной версией.

Однако поначалу я думал, что назначение итераторов работает нормально (обратите внимание, что здесь я больше не разыменовываю итератор).

1.)

// assigning the dereferenced iterator (i.e.: the underlying std::pair)
// resulting in no match for binary '=' operator for const std::string
*pair->first = *itsecond;

Я знаю, что он устарел, так как уже подобрал ключ, и меня интересует только значение. Эта ошибка возникает только из-за того, что ключ является const std :: string Если я не совсем сошел с ума: D

2.)

// assigning the iterator itself
// does not compile as long as itSecond is of type const_iterator ?
// does nothing in case itSecond is of type iterator
pair.first = itSecond;

Это то, чего я на самом деле не понимаю. Как должно вести себя назначение итератора в std :: map? Хотя я программирую на C ++ уже несколько лет, я никогда не сталкивался со сценарием, в котором я делал это для любого контейнера. Я не нашел много информации о назначении итераторов в целом в ходе небольшого исследования.

И, наконец, будет ли еще более элегантный способ сделать то, что я хочу достичь (используя функции C ++ 11, может быть, C ++ 14)?

Ответы [ 3 ]

0 голосов
/ 28 июня 2018

Если C ++ 17 в порядке, вы можете использовать слияние: https://en.cppreference.com/w/cpp/container/map/merge

Но данные не перезаписываются, поэтому вам придется объединить первое со вторым.

0 голосов
/ 28 июня 2018

Ответить на первый вопрос

Как должно вести себя назначение итератора в std :: map?

MapT::Iterator удовлетворяет BidirectionalIterator, что удовлетворяет ForwardIterator, которое удовлетворяет Iterator.

Iterator равно CopyAssignable.

Итак, назначение t = v; сделает

  • Значение t эквивалентно значению v.
  • Значение v не изменяется.

В этом случае замените t на pair.first и v на itSecond. Обратите внимание, что карта не изменяется с этим.

(представьте себе указатели. Конечно, назначение указателей не приведет к изменению содержимого, на которое они указывают)

0 голосов
/ 28 июня 2018

Зачем делать это так сложно? Почему бы просто не

map[itSecond->first] = itSecond->second;

Если они существуют, данные будут изменены. Если ключ не существует, пара будет вставлена.


Также не забывайте, что value_type из std::mapstd::unordered_map в этом отношении) составляет std::pair<const Key, T>.

Поскольку ключ константа , вы не можете просто назначить или скопировать итераторы, вы можете только назначить или скопировать значение.

...