未设置 lambda 返回类型时 std::transform 中的附加副本
Posted
技术标签:
【中文标题】未设置 lambda 返回类型时 std::transform 中的附加副本【英文标题】:additional copy in std::transform when not setting lambda return type 【发布时间】:2018-12-06 17:56:59 【问题描述】:我在 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> vy1;
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 解释的那样,答案是标准禁止函数参数返回的复制省略。
【问题讨论】:
可能重复:***.com/questions/28659879/… 为什么要在这里应用复制省略? 提示:[] (Y const & y) return y;
的返回类型是Y
,而不是Y const &
。
copy elision visible side effect的可能重复
为什么这可能是重复的?由于 Barry 解释的原因,我没有复制省略。这对我来说似乎与您链接到的问题不同
【参考方案1】:
函数参数没有复制省略(见[class.copy.elision]/1.1,重点是我的):
这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):
在具有类返回类型的函数中的return
语句中,当表达式是非易失性自动对象的名称(不是函数参数或由与函数返回类型相同类型(忽略 cv 限定)的处理程序的异常声明([except.handle])),可以通过将自动对象直接构造到函数调用的返回对象中来省略复制/移动操作
lambda 是微不足道的和内联的这一事实并不重要 - 该副本不是省略的候选者。当然,如果编译器可以确定它可以根据 as-if 规则删除副本,它可以这样做 - 但在这种情况下它不能,因为该副本肯定有副作用。
【讨论】:
以上是关于未设置 lambda 返回类型时 std::transform 中的附加副本的主要内容,如果未能解决你的问题,请参考以下文章
no suitable ctr exists to convert from 'int' to 'std::basic_string<char,std::char_tra
c# blazor 避免在委托类型返回 'void' 时使用 'async' lambda
为啥 datadog lambda 检测返回“datadog-lambda-js/handler.handler 未定义或未导出”?