Здравствуйте, .alex, Вы писали:
A>Здравствуйте, watchmaker, Вы писали:
W>>И если ожидается, что ключ должен найтись в ассоциативном контейнере, то может оказаться выгоднее делать два захода: сначала более лёгкий find и лишь в случае его неудачи тяжёлый emplace. Даже несмотря на то, что из-за этого придётся сделать поиск ещё раз. В случае, когда в map'е кешируются какие-то тяжёлые объекты, разница становится очень заметна.
A>Т.е. правильно ли я понял, что метод вставки/редактирования:
A>A>pivot_entry& pivot = (*pm)[{"one", "two", "three", "four"}];
A>
A>будет выделять лишний раз выделять память (если ключ уже присутствует) и оптимальнее перед ним делать find() дабы этого избежать?
Нет, не правильно.
operator[] уже определён через
try_emplace:
https://eel.is/c++draft/associative#map.access-1 И поэтому он не создаёт ноду до получения результатов поиска. То есть из этих соображений никакой экономии не выйдет.
Осталась, правда, ещё одна причина заменять
operator[]: гетерогенный поиск.
До недавнего времени в С++ с ним всё было очень плохо — он просто не поддерживался. И поэтому разницы не было — всё работало одинаково медленно.
Но теперь, если удастся выразить через него некоторые операции, то такая замена может иметь смысл.
Например, в конструкции
(*pm)[{"one", "two", "three", "four"}] у тебя сейчас создаётся tuple из каких-то строк — и если эти строки достаточно длинные, то может потребоваться выделения памяти для их хранения. Потому что
opetator[] принимает аргументом ссылку на
std::tuple<std::wstring, std::wstring, std::wstring, std::wstring>, а
std::wstring — владеющая строка.
А гетерогенный поиск позволит сначала сходить в контейнер с другим типом, который не обязательно требует выделения памяти. Например, с
std::tuple<std::wstring_view, std::wstring_view, std::wstring_view, std::wstring_view>, который не хранит в себе строки и поэтому гарантированно не ходит в кучу, а может быть дёшево сконструирован на стеке (формально тут implementation-defined, но на практике так будет везде).
И, как видно, польза от гетерогенного поиска проявляется из-за возможности не конструировать ключ вообще, если с таким же результатом сравнивать можно другие типы.
А замена
(*pm)[pivot_map_key{"one", "two", "three", "four"}] на
pm->find(pivot_map_key{"one", "two", "three", "four"}) с последующим
pm->emplace(pivot_map_key{"one", "two", "three", "four"}, pivot_entry{}) — это, конечно, бесcмысленно.
Но повторюсь, в стандартном
unordered_map "сломан"
emplace_hint (и нет другого аналогичного механизма), поэтому после неудачного
find нельзя быстро сделать вставку, и из-за этого универсального рецепта сейчас тоже нет: надо в каждом случае смотреть по месту что дешевле.
А пока, вызов
operator[] — хороший выбор по умолчанию. Он не делает откровенно плохих действий. И если тебя устраивает его семантика, то оставляй его.