Здравствуйте, rg45, Вы писали:
R> использование метода find в данном случае нецелесообразно, поскольку метод emplace, так же точно как и метод insert, выполняет вставку только в том случае, если элемент с данным ключом отсутствует в контейнере. Если элемент с таким ключом уже существует, то оба эти метода действуют подобно find.
В целом согласен, но хочется заострить внимание, что
с точки зрения эффективности разница есть и эти методы не подобны find по скорости.
Вызов
find(key) проверит наличие ключа в контейнере. А вызов
emplace(key, value) сначала выделит память под новый узел, потом сконструирует в нём пару ключ-значение, только потом запустит поиск в контейнере, и в случае успешного поиска разрушит этот временный узел.
То есть, по сравнению с find, всегда будет выделение памяти и конструирование копий ключа и значения(!) в нём.
И если ожидается, что ключ должен найтись в ассоциативном контейнере, то может оказаться выгоднее делать два захода: сначала более лёгкий
find и лишь в случае его неудачи тяжёлый
emplace. Даже несмотря на то, что из-за этого придётся сделать поиск ещё раз. В случае, когда в map'е кешируются какие-то тяжёлые объекты, разница становится очень заметна.
(Тут ещё можно огорчится, что к несчастью интерфейс
emplace_hint оказался тоже криво спроектированным в раннем С++ и не может ускорить вставку для хеш-таблиц, убрав необходимость повторного поиска).
А сделать реализацию
emplace без безусловного выделения памяти и создания временных узлов для разных типов либо невозможно, либо настолько сложно, что авторы реализаций STL тоже этого не делают и делать не будут.
Конечно, этот дефект в дизайне
emplace для ассоциативных контейнеров давно известен. И поэтому в С++17 появился вызов
try_emplace c другой семантикой, который как раз позволяет не делать лишней работы, которую делает
emplace, если ожидается, что ключ будет найден.
И уж если заменять пару
find+
emplace, то именно на
try_emplace или на
operator[] (который теперь определён как тонкая обёртка над
try_emplace).