C++中的临时对象
Temporary objects in C++
我正在经历引用返回,遇到了临时对象。我不明白如何识别它们。请使用此示例进行解释:
如果 a
和 b
是同一类的对象,请考虑二进制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 * c
和b * c
的值并将它们存储在某个地方 - 它不能将它们存储在a
或b
或c
中。因此,生成的代码等效于:
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"的惯例只是为了在这个答案中清楚起见。
- 在不复制临时对象的情况下延长其生存期
- 为什么当我们有常量引用时创建临时对象?
- 程序如何'remember'临时对象?
- 返回对临时对象的引用
- 防止临时对象文件访问 MSVC 中的磁盘
- 是否可以在C++中移动临时对象的属性?
- 通过引用传递临时对象
- 临时C++对象是否为左值?
- 临时对象:术语澄清
- 存储对(可能)临时对象的引用是否合法,只要引用不比对象存活?
- 临时对象有身份吗?
- 临时对象上的运算符重载
- 如何在没有 std::move 的情况下移动临时对象
- 临时对象在C++中是不可避免的吗?
- 编译错误:临时对象构造函数中缺少参数
- 为什么在按值返回时创建临时对象,而不是在按值传递给函数参数时创建临时对象
- 我试图创建临时对象的方式有错误吗
- 子表达式中临时对象的生存期
- 对临时对象的Const引用不会延长其生存期
- 为什么引用类型在使用临时对象访问时是左值