Копировать elision при создании объекта внутри emplace () - PullRequest
0 голосов
/ 07 июня 2018

Я вижу много кода на работе, где люди используют emplace и emplace_back с временным объектом, например так:

struct A {
    A::A(int, int);
};

vector<A> v;
vector<A>.emplace_back(A(1, 2));

Я знаю, что весь смысл emplace_back заключается в возможности передавать параметрынапрямую, как это:

v.emplace_back(1, 2);

Но, к сожалению, это не ясно для некоторых людей.Но не будем останавливаться на этом ....

Мой вопрос: может ли компилятор оптимизировать это и пропустить создание и копирование?Или я действительно должен попытаться исправить эти случаи?

Для справки ... мы работаем с C ++ 14.

Ответы [ 4 ]

0 голосов
/ 07 июня 2018

Простой ответ - нет;elision не работает с идеальной пересылкой.Но это , так что ответ на самом деле да.

Требуется прикосновение к шаблону:

struct A {
  A(int, int){std::cout << "A(int,int)\n"; }
  A(A&&){std::cout<<"A(A&&)\n";}
};

template<class F>
struct maker_t {
  F f;
  template<class T>
  operator T()&&{ return f(); }
};

template<class F>
maker_t<std::decay_t<F>> maker( F&& f ) { return {std::forward<F>(f)}; }

vector<A> v;
v.emplace_back(maker([]{ return A(1,2); }));

живой пример .

Выход - один вызов A(int,int).Движение не происходит.В создание даже не требует, чтобы конструктор перемещения существовал (но вектор делает это, так как считает, что может потребоваться переместить элементы в уже выделенном буфере).В ходы просто исключены.

0 голосов
/ 07 июня 2018

Мой вопрос: может ли компилятор оптимизировать это и пропустить создание и копирование?Или я действительно должен попытаться исправить эти случаи?

В общем случае избежать копии невозможно.Поскольку emplace_back принимает путем пересылки ссылок, он должен создавать временные ссылки с чисто стандартной точки зрения.В конце концов, эти ссылки должны быть привязаны к объектам.

Elision Copy - это набор правил, который позволяет избежать конструктора копирования (или перемещения) и копирования, даже если у конструктора и соответствующего деструктора есть сторона-последствия.Это относится только к конкретным обстоятельствам.И передача аргументов по ссылке не относится к числу таких.Таким образом, для нетривиальных типов, где копии объекта не могут быть встроены правилом «как будто», руки компилятора связаны, если он стремится быть стандартным конформантом.

0 голосов
/ 07 июня 2018

Я просто хочу добавить

Прекрасный 5-минутный молниеносный разговор о копировании elision и RVO от Jon Kalb https://youtu.be/fSB57PiXpRw

Кроме того, вы можете получить разные результаты, используя разные компиляторы gcc, clang или icc

См. Проводник компилятора , попробуйте различные компиляторы и настройки и убедитесь сами

https://godbolt.org/g/Yjo9qA

0 голосов
/ 07 июня 2018

Может ли компилятор оптимизировать этот процесс и пропустить создание и копирование?

Не обязательно, чтобы была вовлечена копия.Если доступен конструктор перемещения, будет выполнено перемещение.Это нельзя оптимизировать, так как в случае прямой инициализации просто вызывается конструктор init, в то время как в другом случае конструктор перемещения будет вызываться дополнительно (включая его побочные эффекты).

Поэтому, если возможно,Вы должны рефакторинг этих кодов.

...