LINUX.ORG.RU

insert or update by std::map iterator

 ,


0

1

Имеется:

std::map<K,V> cache;
void updateCache(K k, V v) {
    auto it = cache.find(k);
    if (it == cache.end() || it->second.value != v) {
        cache[k] = v;
        persistCache();
    }
}

Как бы мне в строчке cache[k] = v; избежать повторного поиска ключа в map, а заюзать вместо этого уже имеющийся it?

★★★★★

Искать с помощью map::lower_bound, а получающийся итератор передавать как hint в map::insert

iterator insert( const_iterator hint, const value_type& value );

rupert ★★★★★
()
Последнее исправление: rupert (всего исправлений: 1)
Ответ на: комментарий от rupert

Про lower_bound() я бы хрен догадался. Но оно ж возвращает позицию для вставки, и если вставка ожидается куда-то в середину дерева/хеш-таблицы, оно вернёт НЕ end(). Как тогда узнать, найден элемент или нет?

Нашёл: вместо it != cache.end() надо будет писать it != cache.end() && it->first == k (ну или через key_comp()).

В общем, ясно. Сенькс. :)

dimgel ★★★★★
() автор топика
Ответ на: комментарий от dimgel

А могли бы из lower_bound() возвращать pair<iterator, bool> с флагом «точное совпадение», чтобы избежать повторного сравнения ключей…

dimgel ★★★★★
() автор топика
Ответ на: комментарий от dimgel

А могли бы из lower_bound() возвращать pair<iterator, bool> с флагом «точное совпадение», чтобы избежать повторного сравнения ключей…

Это была бы пессимизация: std::map работает в терминах less (в подавляющем большинстве случаев Class::operator<), и равенство задаётся как !(a < b) && !(b < a). Такой bool требовал бы лишнего сравнения всегда.

ПыСы. Рекомендую избавиться от привычки таскать параметры by-value, и посмотреть на std::optional<>.

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

Это была бы пессимизация: std::map работает в терминах less

Понятно. Ну тогда для unordered_map было бы актуально.

Рекомендую избавиться от привычки таскать параметры by-value,

Нет такой привычки. В вопросе – псевдокод для краткости.

и посмотреть на std::optional<>.

А это тут при чём?

Как бы дико это ни звучало, но чаще всего меня на плюсах бомбит от того, что я не могу давать optional-переменным имена x_? (как я привык писать на скале), приходится пердолиться с громоздким и нечитабельным x_opt.

dimgel ★★★★★
() автор топика
Последнее исправление: dimgel (всего исправлений: 2)
Ответ на: комментарий от dimgel

и посмотреть на std::optional<>.

А это тут при чём?

typedef std::map<К, std::optional<V> > MyMap;

Могу разжевать дальше, но идея должна быть уже прозрачна.

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

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

dimgel ★★★★★
() автор топика
Последнее исправление: dimgel (всего исправлений: 1)
Ответ на: комментарий от dimgel

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

auto& val = cache[k];
if (!val) {
   val.emplace(v);
   persistCache();
}

Зачастую лучше чем lower_bound + hinted insert.

bugfixer ★★★★★
()
Ответ на: комментарий от dimgel

Ну, там ещё строго говоря надо

else if (*val != v) {
   *val = v;
   persistCache();
}

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

ПыСы. А Вы что, реально весь cache персистать собрались по update каждого элемента? Вот это реально выглядит подозрительно.

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

А Вы что, реально весь cache персистать собрались по update каждого элемента? Вот это реально выглядит подозрительно.

В вопросе псевдокод, персист – для примера, там другие тяжёлые действия. Да и сам вопрос на самом деле был больше для успокоения души: там и кеш небольшой, и работа с ним на фоне всей остальной возни – O(0), простите господи за мой французский. Вроде давно уже «вернулся» на плюсы, а пальцы до сих пор как чужие. Вот из таких мелочей и накапливаю комфорт понимания.

dimgel ★★★★★
() автор топика
Последнее исправление: dimgel (всего исправлений: 1)
Ответ на: комментарий от dimgel

Не используй find. Используй сразу insert. Optional тут не нужен.

iliyap ★★★★★
()
Ответ на: комментарий от Siborgium

Во, «я прям как чувствовал» (c) что должно же быть что-то такое «в лоб». Сенькс. :)

Эк мне накидали вариантов на один простой вопрос… Полагаю, в промышленной ситуации тут было бы сравнение по количеству сравнений/копирований ключей/значений, и т.д.

dimgel ★★★★★
() автор топика
Последнее исправление: dimgel (всего исправлений: 1)
Ответ на: комментарий от Siborgium

Не ты один, жми «показать удалённые комментарии». =) КакаяИрония.jpeg.

dimgel ★★★★★
() автор топика
Ответ на: комментарий от dimgel

Эк мне накидали вариантов на один простой вопрос… Полагаю, в промышленной ситуации тут было бы сравнение по количеству сравнений/копирований ключей/значений, и т.д.

Вариант с try_emplace() by @Siborgium здесь самый чистенький если cxx-17 доступен (optional легко бэкпортится).

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.