C++返回对临时库的引用或将其存储在对象中

C++ return reference to temporaries or store them in objects

本文关键字:存储 对象 引用 返回 C++      更新时间:2023-10-16

考虑以下处理常量引用的代码:

const int & func (const int &x)
{
return x;
}
struct Foo {
Foo (const int &x)
: m_x(x) {}
const int & getX ()
{ return m_x; }
const int &m_x;
};

我想知道以下哪一项(如果有的话)现在是允许的:

int x = func(int(7));
int y = Foo(int(7)).getX();

是否可以保证临时int对象在被分配或getX使用之前仍然存在?。

更新:所以看起来这是安全的,但为什么呢?

  1. 是因为临时库递归绑定到常量引用,并且只要绑定到它们的引用存在,就保证存在吗
  2. 还是因为它们保证在完整表达的持续时间内存在

考虑存储指针而不是引用的边缘情况:

struct Foo {
Foo (const int &x)
: m_x(&x) {}
const int & getX ()
{ return *m_x; }
const int *m_x;
};
int y = Foo(int(7)).getX();

看来,如果情况1)是正确的,这将不起作用。但如果情况2)是正确的,它会的。

两者都是安全的,因为您将值复制到xy中。临时值在完整表达式结束之前一直有效。

12.2临时物品

4)有两种情况下,临时存储在不同点的完整表达结束。第一个上下文当调用默认构造函数来初始化大堆如果构造函数有一个或多个默认参数,则在默认参数表达式中创建的临时变量将被销毁从构造函数返回后立即执行。

5) 第二个上下文是当引用绑定到临时。临时引用是绑定的或临时的,它是引用绑定到的子对象在除以下规定外的参考。临时绑定到构造函数的ctor初始值设定项(12.6.2)中的引用成员仍然存在直到构造函数退出。临时绑定到引用函数调用(5.2.2)中的参数将一直持续到包含调用的完整表达式。临时绑定到函数返回语句(6.6.3)中的返回值一直持续到则函数退出。在所有这些情况下初始化引用的表达式的求值,除了引用绑定到的临时创建它们的完整表达式的末尾按照相反的顺序完成它们的建造。如果生命引用绑定到的两个或多个临时目录的结尾位于在同一点上,这些临时仓库在按照相反的顺序完成它们的建造。此外对附于参考文件的临时文件的销毁应考虑用静态或自动存储持续时间(3.7.1,3.7.2);也就是说,如果obj1是在创建临时对象之前创建的具有静态或自动存储持续时间的对象,则临时对象应在obj1被销毁之前被销毁;如果obj2是具有在临时创建时,临时应在obj2销毁后销毁。[示例:

class C 
{ 
/ / ... 
public : 
C(); 
C(int ); 
friend C operator +(const C&, const C&); 
~C(); 
}; 
C obj1 ; 
const C& cr = C (16)+ C (23); 
C obj2 ; 

表达式C(16)+C(23)创建三个临时变量。第一个临时T1为了保持表达式C(16)的结果保持表达式C(23)的结果和第三临时T3保持这两个表达式相加的结果。这个临时T3被绑定到引用cr。它是未指定的首先创建T1还是T2。在T1为保证T2在T1之前被破坏。临时T1和T2被绑定到运算符+;这些临时仓库在全库结束时被销毁包含对运算符+的调用的表达式。临时T3绑定到参考cr在cr寿命结束时被破坏,也就是说,在节目结束。此外,T3为destroyed考虑了其他物体的销毁顺序具有静态存储持续时间。也就是说,因为obj1是构造的在T3之前,并且T3在obj2之前构造,则保证obj2在T3之前被破坏并且T3在obj1之前被破坏。--结束示例]

两者都是安全的。临时可以绑定到const引用,并且它们一直持续到绑定临时的表达式执行为止。在这种情况下,您将它绑定到构造函数参数,并且它一直存在到构造函数的右大括号。

一个类似的现象是使用临时函数参数作为const引用的默认函数参数:

void foo(const someclass& bla = someclass()); // bind const ref with default constructed someclass