# V837. The 'emplace' / 'insert' function does not guarantee that arguments will not be copied or moved if there is no insertion. Consider using the 'try_emplace' function.

Анализатор обнаружил использование функции 'emplace' / 'insert' ассоциативного контейнера стандартной библиотеки ('std::map', 'std::unordered_map'), у которого существует функция 'try_emplace'. Функция 'emplace' / 'insert' может привести к копированию или перемещению аргументов, даже если вставки не произойдёт (элемент с указанным ключом уже присутствует в контейнере). Это может привести к замедлению программы, а в случае перемещения аргумента — к преждевременному освобождению ресурсов.

В зависимости от реализации стандартной библиотеки, функция 'emplace' / 'insert' перед проверкой наличия элемента с указанным ключом может создать временный объект типа 'std::pair', в который аргументы функции будут скопированы или перемещены. Начиная со стандарта С++17, для контейнеров 'std::map' и 'std::unordered_map' была добавлена функция 'try_emplace'. Она гарантирует, что если элемент с указанным ключом уже существует, то аргументы функции не будут скопированы или перемещены.

Рассмотрим пример кода:

    class SomeClass
    {
      std::string name, surname, descr;

    public:
      // User-defined constructor
      SomeClass(std::string name, std::string surname, std::string descr);

      // ....
    };

    std::map<size_t, SomeClass> Cont;

    bool add(size_t id,
             const std::string &name,
             const std::string &surname,
             const std::string &descr)
    {
      return Cont.emplace(id, SomeClass { name, surname, descr })
                 .second;
    }

В примере в некоторый контейнер 'Cont' производят вставку объекта типа 'SomeClass' по ключу 'id'. Если объект по такому ключу уже ранее был добавлен, могут быть произведены следующие лишние операции:

- 3 вызова конструктора копирования строки при конструировании временного объекта типа 'SomeClass';
- 3 вызова конструктора перемещения строки при идеальной передаче временного объекта типа 'SomeClass' во временный объект типа 'std::pair<const size_t, SomeClass>'.

Используя функцию 'try_emplace' вместо 'emplace', можно избежать лишних операций по формированию временного объекта типа 'std::pair<const size_t, SomeClass>':

    bool add(size_t id,
             const std::string &name,
             const std::string &surname,
             const std::string &descr)
    {
      return Cont.try_emplace(id, SomeClass { name, surname, descr })
                 .second;
    }

Использование 'try_emplace' позволяет также конструировать объекты "по месту" внутри ассоциативного контейнера. В примере тип 'SomeClass' не является агрегатным и содержит определённый пользователем конструктор, поэтому можно избежать также и 3 вызовов конструкторов копирования строк:

    bool add(size_t id,
             const std::string &name,
             const std::string &surname,
             const std::string &descr)
    {
      return Cont.try_emplace(id, name, surname, descr)
                 .second;
    }

Начиная с C++20, функция 'try_emplace' работает также и с агрегатными типами:

    struct SomeClass
    {
      std::string name, surname, descr;
    };

    bool add(size_t id,
             const std::string &name,
             const std::string &surname,
             const std::string &descr)
    {
      return Cont.try_emplace(id, name, surname, descr)
                 .second;
    }