C++中的临时对象

Temporary objects in C++

本文关键字:临时对象 C++      更新时间:2023-10-16

我正在经历引用返回,遇到了临时对象。我不明白如何识别它们。请使用此示例进行解释:

如果 ab 是同一类的对象,请考虑二进制operator+。如果在表达式中使用它,例如 f(a+b) ,则a+b将成为临时对象,并且f的形式必须为 f(const <class name>&)f(<class name>) 。它不能是形式f(<class name>&)但是,(a+b).g()完全没问题,g()甚至可以更改a+b返回的对象的内容。

当你说f(a + b)时,f的参数需要绑定到调用函数的值,并且由于该值是右值(是具有非引用返回类型的函数调用的值)*,因此参数类型必须是常量左值引用,右值引用或非引用。

相反,当你说(a + b).g()时,临时对象被用作成员函数调用中的隐式实例参数,它不关心值类别。可变值绑定到非常量和常量成员函数,常量值仅绑定到常量成员函数(对于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

*) 本例中的重载运算符就是这种情况,内置二进制运算符也是如此。当然,您可以制作产生左值的重载运算符,尽管违反通用约定可能会被认为非常混乱。

你的困惑不是来自你无法识别临时对象,在这两种情况下,结果都是a+b是临时对象,而是错误的假设,即non const方法需要左值并且不接受临时对象,这是不正确的。

对于一个简单的情况,请考虑以下代码段:

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需要两个整数,所以程序必须计算a * cb * c的值并将它们存储在某个地方 - 它不能将它们存储在abc中。因此,生成的代码等效于:

int lhsParam = a * c;
int rhsParam = b * c;
return func(lhsParam, rhsParam);

同样,在func()结束时,我们返回一个计算值,lhs + rhs 。编译器必须将其存储在新位置。

对于整数等,这似乎很简单,但请考虑

int function(std::string filename);
function("hello");

filename必须是std::string,但你通过了const char*。所以编译器所做的是:

std::string filenameParam = "hello"; // construct a new object
function(filenameParam);

就像前面的例子一样,但这次希望更清楚我们正在构造一个临时对象。

注意:称它们为"somethingParam"的惯例只是为了在这个答案中清楚起见。