c++ - 不设置 lambda 返回类型时在 std::transform 中的附加拷贝

标签 c++ gcc c++17 copy-elision

我在使用 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 的第二个拷贝(在转换中)会发生?我可以通过将一元 lambda 的返回类型设置为引用来摆脱它

-> auto const &

我认为 lambda operator() 和/或复制省略的内联特性会处理“无用”的复制。

编辑:正如 Barry 所解释的,答案是标准禁止函数参数返回的复制省略。

最佳答案

函数参数中没有复制省略(参见 [class.copy.elision]/1.1,重点是我的):

This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function parameter or a variable introduced by the exception-declaration of a handler ([except.handle])) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function call's return object

lambda 是微不足道且内联的事实并不重要 - 该拷贝不是省略的候选者。当然,如果编译器可以确定它可以根据 as-if 规则删除拷贝,它可以这样做——但在这种情况下不能,因为该拷贝肯定有副作用。

关于c++ - 不设置 lambda 返回类型时在 std::transform 中的附加拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53657186/

相关文章:

c - IOCCC 1987/weSTLey.c - GCC 的左值问题

linux - gdb:检查堆栈和小端澄清

c++ - 在 boost::unordered_multimap 中循环遍历 equal_range

带有类对象的 C++ vector push_back

java - Java 开发人员学习 C++ 的最佳方法是什么

c++ - 全局对象是否保证在所有线程本地存储对象被销毁后被销毁?

c++ - 传递一个自由函数来调用?

C++ 指针深拷贝

c++ - MINGW BOOST 链接失败

c++ - C++推导的返回类型在定义之前不能使用