﻿# V823\. Decreased performance\. Object may be created in\-place in a container\. Consider replacing methods: 'insert' \-\> 'emplace', 'push\_\*' \-\> 'emplace\_\*'\.

Анализатор обнаружил потенциальное использование менее эффективного метода\. При вставке временного объекта в контейнер при использовании методов 'insert' / 'push\_\*' он конструируется снаружи контейнера и затем перемещен/скопирован внутрь контейнера\.

Методы 'emplace' / 'emplace\_\*' в свою очередь позволяют устранить один избыточный вызов конструктора перемещения / копирования и создают объект "по месту" внутри контейнера, идеально передавая параметры функции конструктору объекта\.

Анализатор предлагает следующие замены:

* insert \-\> emplace
* insert\_after \-\> emplace\_after
* push\_back \-\> emplace\_back
* push\_front \-\> emplace\_front

Пример кода:

```cpp
std::string str { "Hello, World" };
std::vector<std::string> vec;
std::forward_list<std::string> forward_list;
std::list<std::string> list;
std::map<std::string, std::string> map;

....

vec.push_back(std::string { 3, 'A' });
forward_list.push_front(std::string { str.begin(), str.begin() + 6 });
list.push_front(str.substr(7));
list.push_back(std::string { "Hello, World" });
map.insert(std::pair<std::string, std::string> { "Hello", "World" });
```

Оптимизированный код:

```cpp
std::vector<std::string> vec;
std::forward_list<std::string> forward_list;
std::list<std::string> list;
std::map<std::string, std::string> map;

....

vector.emplace_back(3, 'A');
forward_list.emplace_front(string.begin(), string.begin() + 6);
list.emplace_front(str.begin() + 7, str.end());
list.emplace_back("Hello, World");
map.emplace("Hello", "World");
```

В некоторых случаях такая замена может привести к потере базовой гарантии безопасности исключений\. Рассмотрим пример:

```cpp
std::vector<std::unique_ptr<int>> vectUniqP;
vectUniqP.push_back(std::unique_ptr<int>(new int(0)));
auto *p = new int(1);
vectUniqP.push_back(std::unique_ptr<int>(p));
```

В таком случае замена 'push\_back' на 'emplace\_back' может привести к утечке памяти, если 'emplace\_back' бросит исключение в связи с отсутствием памяти\. Анализатор не выдает срабатывания на подобные случаи и не предлагает замену\. Если же код был изменен на ошибочный, анализатор выдаст предупреждение [V1023](https://pvs-studio.ru/ru/docs/warnings/v1023/)\.

Иногда замена вызовов методов 'insert' / 'push\_\*' на их аналог 'emplace' / 'emplace\_\*' не принесет оптимизации:

```cpp
std::string foo()
{
  std::string res;
  // doing some heavy stuff
  return res;
}

std::vector<std::string> vec;
....
vec.push_back(foo());
```

В этом примере метод 'emplace\_back' будет иметь такую же эффективность, что и вставка элемента через 'push\_back'\.  Однако, предупреждение всё равно выдаётся для единообразия\. Во всех подобных ситуациях рационально сделать замену, чтобы код смотрелся единообразно и при его просмотре не приходилось каждый раз задумываться, стоит использовать 'emplace\*' или нет\. Если пользователь не согласен с таким подходом, он может рассматривать подобные предупреждения как ложные и подавлять их\.

**Примечание\.** К описанной здесь рекомендации стоит подходить разумно, а не формально\. Например, замена

```cpp
widgets.push_back(Widget(foo, bar, baz));
// на
widgets.emplace_back(Widget(foo, bar, baz));
```

не даёт никакого выигрыша в скорости работы программы\. Более того, использование 'emplace\_back' может замедлить скорость компиляции кода\. Подробнее эта тема освящена в статье "[Don't blindly prefer emplace\_back to push\_back](https://quuxplusone.github.io/blog/2021/03/03/push-back-emplace-back/)"\. Наша команда выражает Arthur O'Dwyer благодарность за эту публикацию\.