我正在通过引用返回并遇到临时对象。我不明白如何识别它们。请使用此示例进行说明:
如果a
和b
是同一类的对象,请考虑 binary operator+
。如果您在表达式中使用它f(a+b)
,则 , thena+b
将成为临时对象并且f
必须以f(const <class name>&)
or的形式出现f(<class name>)
。它不能是形式f(<class name>&)
但是,(a+b).g()
在哪里g()
甚至可以更改由a+b
.
当您说f(a + b)
时,参数f
需要绑定到调用函数的值,并且由于该值是右值(具有非引用返回类型的函数调用的值)*,因此参数类型必须是const-lvalue-reference、右值引用或非引用。
相比之下,当你说 时(a + b).g()
,临时对象被用作成员函数调用中的隐式实例参数,它不关心值类别。可变值绑定到非 const 和 const 成员函数,而 const 值仅绑定到 const 成员函数(对于 const 也是如此volatile
)。
实际上,C++11确实添加了一种方法来限定隐式实例参数的值类别,如下所示:
struct Foo()
{
Foo operator+(Foo const & lhs, Foo const & rhs);
void g() &; // #1, instance must be an lvalue
void g() &&; // #2, instance must be an rvalue
}
Foo a, b;
a.g(); // calls #1
b.g(); // calls #1
(a + b).g(); // calls #2
*) 这适用于本例中的重载运算符,也适用于内置二元运算符。您当然可以制作产生左值的重载运算符,尽管违反常见约定可能会被认为非常混乱。
对于一个简单的案例,请考虑以下代码:
int func(int lhs, int rhs)
{
return lhs + rhs;
}
int main() {
int a = 1, b = 2, c = 3;
return func(a * c, b * c);
}
因为 func 需要两个整数,所以程序必须计算 and 的值a * c
并将b * c
它们存储在某个地方——它不能将它们存储在a
orb
或c
中。所以生成的代码等价于:
int lhsParam = a * c;
int rhsParam = b * c;
return func(lhsParam, rhsParam);
同样,在最后func()
我们返回一个计算值,lhs + rhs
。编译器必须将它存储在一个新的地方。
对于整数等,这似乎很简单,但请考虑
int function(std::string filename);
function("hello");
filename
必须是 a std::string
,但你通过了 a const char*
。所以编译器所做的是:
std::string filenameParam = "hello"; // construct a new object
function(filenameParam);
就像前面的例子一样,但这次希望更清楚的是我们正在构建一个临时对象。
注意:称它们为“somethingParam”的约定只是为了在这个答案中清晰。
您的困惑不是因为您无法识别临时对象,在这两种情况下a+b
都是临时对象,而是错误假设非 const 方法需要左值并且不接受临时对象,这是不正确的。