尽管按名称返回,为什么局部变量仍被复制?

Aka*_*ash 7 c++ c++11

在下面的代码片段中,return s给出了警告local variable 's' will be copied despite being returned by name [-Wreturn-std-move]。为什么会这样呢?

我使用此 lambda 函数的目标是获取输入字符串的所有权,然后在通过 RVO 或移动语义修改后返回它。我真的很想避免任何复制。

const auto to_upper = [](std::string&& s) {
    std::transform(s.begin(), s.end(), s.begin(), 
        [](unsigned char c){ return std::toupper(c); }
    );
    return s;
};
Run Code Online (Sandbox Code Playgroud)

返回std::move(s)orstd::forward<std::string>(s)将解决问题,但我认为这是没有必要的,因为编译器可以省略复制构造函数的使用。另外,我认为我应该使用std::forward,但哪一个是正确的,为什么?

Hol*_*Cat 2

如果函数按值返回,并且返回的变量与返回类型具有相同的类型,则有一条规则允许局部变量(包括函数参数)在返回时隐式移动(而不是复制)。

\n

该警告告诉您,在这种情况下不会发生这种隐式移动,因为s是引用,并且该规则不适用于引用。

\n
\n
\n

我想我应该使用 std::forward

\n
\n

不,您应该使用std::move,因为您的参数不是转发引用。仅当是模板参数(或)T &&时才被视为转发引用,在调用时会推导出该参数。Tauto

\n
\n

看来 C++20 中的规则已更改,右值引用现在也可以隐式移动。从C++20开始,std::move这里可以去掉。

\n

这受以下因素管辖:

\n
\n

[class.copy.elision](C++20)

\n

3隐式可移动实体是具有自动存储持续时间的变量,它可以是非易失性对象,也可以是对非易失性对象类型的右值引用。\n在以下复制初始化上下文中,在尝试移动操作之前首先考虑移动操作复制操作:

\n

(3.1) \xe2\x80\x94 如果 return ([stmt.return]) 或 co_\xc2\xadreturn ([stmt.return.coroutine]) 语句中的表达式是一个(可能带括号的)id 表达式,它命名了在最里面的封闭函数或 lambda 表达式的主体或参数声明子句中声明的隐式可移动实体,或者...

\n
\n

C++20 之前的措辞有所不同,它只允许“自动对象”(而不是引用)。

\n