﻿# 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'\. Она гарантирует, что если элемент с указанным ключом уже существует, то аргументы функции не будут скопированы или перемещены\.

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

```cpp
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 вызова конструктора перемещения строки при [идеальной передаче](https://pvs-studio.ru/ru/blog/terms/6515/) временного объекта типа 'SomeClass' во временный объект типа 'std::pair<const size\_t, SomeClass\>'\.

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

```cpp
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' не является [агрегатным](https://en.cppreference.com/w/cpp/language/aggregate_initialization#Definitions) и содержит определённый пользователем конструктор, поэтому можно избежать также и 3 вызовов конструкторов копирования строк:

```cpp
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' работает также и с агрегатными типами:

```cpp
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;
}
```