дополнительная копия в std :: transform, когда не устанавливается лямбда-тип возврата - PullRequest
0 голосов
/ 06 декабря 2018

Я боролся со следующим примером кода с gcc 7.3 и c ++ 17: https://wandbox.org/permlink/UT3RR9jgRmr3VBWv

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

struct Y {
  Y ( int const & s ) : y(s) { std::cout << "construct y\n"; }
  Y ( Y const & yi ) : y(yi.y) { std::cout << "copy y\n"; }
  Y ( Y && yi ) noexcept : y(yi.y) { std::cout << "move y\n"; }
  int y;
};

struct X {
  X ( Y const & yi ) : x(yi.y) { std::cout << "construct x\n"; } 
  X ( X const & xi ) : x(xi.x) { std::cout << "copy x\n"; }
  X ( X && xi ) noexcept : x(xi.x) { std::cout << "move x\n"; }
  int x;
};

int main () {
  std::vector<Y> vy{1};
  std::vector<X> vx;
  vx.reserve(vy.size());
  std::cout << "begin transform\n";
  std::transform(begin(vy), end(vy), std::back_inserter(vx), [] (auto const & y) { return y; });
}

Вывод

construct Y  
copy Y  
begin transform  
copy Y  
construct X  
move X

Почему эта вторая копияY (в преобразовании) случится?Я могу избавиться от него, установив тип возвращаемого значения унарной лямбды на ссылку

-> auto const &

Я думал, что встроенная природа лямбда-оператора () и / или копирования elision позаботятся о «бесполезном»"копия.

РЕДАКТИРОВАТЬ: Как объяснил Барри, ответ заключается в том, что стандарт запрещает исключение копирования возвращений аргументов функции.

1 Ответ

0 голосов
/ 06 декабря 2018

Нет разрешения копирования из параметров функции (см. [class.copy.elision] /1.1, emphasisis mine):

Это исключение операций копирования / перемещения,называется elision copy, разрешается в следующих обстоятельствах (которые могут быть объединены для удаления нескольких копий):

  • в операторе return в функции с типом возвращаемого класса, когда выражение являетсяимя энергонезависимого автоматического объекта (, отличного от параметра функции или переменной, введенной в объявлении исключения обработчика ([исключением. дескриптора])) с тем же типом (игнорируя квалификацию cv)в качестве типа возврата функции, операция копирования / перемещения может быть опущена путем создания автоматического объекта непосредственно в возвращаемом объекте вызова функции

Тот факт, что лямбда является тривиальной и встроенной, неДело в том, что эта копия не является кандидатом на избрание.Конечно, если компилятор может определить, что он может удалить копию в соответствии с правилом «как будто», он может это сделать, но в этом случае это невозможно, поскольку эта копия определенно имеет побочные эффекты.

...