函数不返回右值或左值。值类别适用于表达式。所以调用函数的表达式可能是右值或左值。在这种情况下,表达式getName()
是一个右值表达式,因为该函数getName
按值返回一个对象。这来自§5.2.2/10:
如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值,如果结果类型是对对象类型的右值引用,则为 xvalue,否则为纯右值。
您的函数结果类型不是左值或右值引用,因此函数调用是纯右值。prvalue 表达式是 rvalue 表达式的子集。
将使用移动构造函数(除非它被省略,它可能是)。那是因为getName()
是一个右值,所以它的构造函数std::string
采用右值引用将更好地匹配参数。请注意,即使省略了移动构造,移动构造函数仍必须可访问。也就是说,即使没有省略,代码也必须是可编译的。
一般来说,复制或移动省略的优化将完全摆脱任何复制或移动。因此,它当然比实际移动要快。如果一个动作被省略,实际上什么都不会发生。该动作不会发出任何代码。编译器通过直接在对象将被复制或移动到的位置构造对象来实现这一点。
值得一提的是,这也可以等效优化:
string getName () {
std::string str("meme");
return str;
}
string name = getName();
在这里,将省略两个动作(涉及通常所说的命名返回值优化)。这里有两点需要考虑。首先,return str;
满足复制/移动省略的标准(§12.8/31):
这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以组合起来消除多个副本):
- 在具有类返回类型的函数的 return 语句中,当表达式是具有与函数返回类型相同的 cv 非限定类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作
- ...
其次,虽然str
它是一个左值,但它仍然会被移出,因为它符合标准给出的特殊情况(第 12.8/32 节):
当满足或将满足复制操作的省略标准时,除了源对象是函数参数的事实,并且要复制的对象由左值指定时,选择复制的构造函数的重载决策是首先执行好像对象是由右值指定的。