作者:真理难辩_175 | 来源:互联网 | 2022-12-10 12:26
1> xskxzr..:
因为返回具有自动存储持续时间的对象的名称被视为返回对象的右值.请注意,这仅适用于return语句中的表达式(可能是括号,不包括大括号)名称,return u;
或者return (u);
,因此return {u};
通常工作,即调用复制构造函数.
标准[class.copy.elision]/3中的相关部分:
在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:
如果return语句([stmt.return])中的表达式是一个(可能带括号的)id-expression,它指定一个对象,该对象具有在最内层封闭函数或lambda-expression的body或parameter-declaration-clause中声明的自动存储持续时间, 要么
...
首先执行重载决策以选择副本的构造函数,就好像该对象是由rvalue指定的一样.
2> sandthorn..:
这是一种braced-init-list.[dcl.init.list] /1.3
更具体地说,它是一个" expr-or- braced -init-list [dcl.init]/1
一个的return语句 " [stmt.return]/2
带有任何其他操作数的return语句只能在返回类型不是cv void的函数中使用; return语句初始化glvalue结果或(显性或隐性)函数调用的prvalue结果对象副本初始化从
操作数.
从这一点开始,让我提一下xskxzr的答案,提到[class.copy.elision]/3
在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:
如果return语句([stmt.return])中的表达式是一个(可能带括号的)id-expression,它指定一个对象,该对象具有在最内层封闭函数或lambda-expression的body或parameter-declaration-clause中声明的自动存储持续时间, 要么
在正常的人类话语中,由于braced-init-list调用u
碰巧是左值,因此调用副本而不是移动的原因.
所以,你可能想知道,如果支撑-初始化列表调用u
是右值 ...
return {std::move(u)};
嗯,之后u
被转移到一个新的rvalue UserName
和复制elision工作.
所以这需要一举一动
return u;
godbolt.org/g/b6stLr
wandbox.org/permlink/7u1cPc0TG9gqToZD
#include
#include
struct UserName
{
int x;
UserName() : x(0) {};
UserName(const UserName& other) : x(other.x) { std::cout <<"copy " < CreateUser()
{
UserName u;
return u; // this one moves UserName
}
std::optional CreateUser_listinit()
{
UserName u;
auto whatever{u};
return whatever;
}
std::optional CreateUser_listinit_with_copy_elision()
{
UserName u;
return {u};
}
std::optional CreateUser_move_listinit_with_copy_elision()
{
UserName u;
return {std::move(u)};
}
int main()
{
std::cout <<"CreateUser() :\n";
[[maybe_unused]] auto d = CreateUser();
std::cout <<"\nCreateUser_listinit() :\n";
[[maybe_unused]] auto e = CreateUser_listinit();
std::cout <<"\nCreateUser_listinit_with_copy_elision() :\n";
[[maybe_unused]] auto f = CreateUser_listinit_with_copy_elision();
std::cout <<"\nCreateUser_move_listinit_with_copy_elision() :\n";
[[maybe_unused]] auto g = CreateUser_move_listinit_with_copy_elision();
}
打印
CreateUser() :
move 0
CreateUser_listinit() :
copy 0
move 0
CreateUser_listinit_with_copy_elision() :
copy 0
CreateUser_move_listinit_with_copy_elision() :
move 0