临时对象存储在哪里?

20
4个回答

11

这个标准没有规定任何内存区域(堆栈)供它们使用,但它们就像本地变量一样,“自动存储”,也就是在表达式结束时(或者绑定到一个ref-to-const时更长时间),它们就被销毁了。

大多数实现将它们存储在堆栈中,就像本地变量一样。

编辑:

正如James Kanze所指出的:如果通过ref-to-const扩展一个临时对象的生命周期,它的存储位置在大多数实现中有点取决于该引用的存储位置。也就是说,在引用位于静态存储区时,临时对象也会位于静态存储区(在gcc上刚刚确认)。虽然在标准意义上仍然是一个临时对象,但我认为它在直观的英语意义上是否为临时对象是可以争议的。


@LuchianGrigore:所以在你的例子中,临时变量会在foo();返回后继续存在吗?你能引用标准中允许这种情况发生的部分吗? - PlasmaHH
@Luchian Grigore 在这里https://dev59.com/yV_Va4cB1Zd3GeqPWLcb说它应该是表达式的结尾,不是吗? - Mihran Hovsepyan
@PlasmaHH 是的 - 12.2/2。此外,请参见这个问题:https://dev59.com/TGoy5IYBdhLWcg3wlvGX#8451249 - Luchian Grigore
@PlasmaHH 我并没有说变量在函数之后存在。我只是说,当将临时参数传递时,生命周期可以延长超出表达式的结尾。 - Luchian Grigore
2
有一些情况几乎可以确定它不在堆栈上。考虑这样的情况:static MyType const& x = MyType();。在这种情况下(也是我能想到的唯一一种情况),临时变量可能与静态数据在同一空间中。 - James Kanze
显示剩余10条评论

7
这取决于它们的生命周期。在函数内创建的临时变量,如果不将其绑定到本地静态引用以延长其生命周期,则很可能会在堆栈上创建。将临时变量绑定到本地静态引用的情况下,它们很可能存储在程序二进制文件的 .data 部分中。对于绑定到非本地引用的临时变量也是如此。在初始化非本地变量(除了被引用绑定的变量)期间创建的临时变量应该在生成该非本地变量值的函数的堆栈上。

在解除异常期间表示抛出对象的异常对象也是临时变量。这些通常驻留在堆上。


应注意,我的回答忽略了线程本地变量的存在。有经验的人应该站出来澄清。 - Johannes Schaub - litb
实际上,尽管 OP 可能没有考虑到它们,但异常也是临时的。C++11 中的初始化列表也是如此。至于线程本地变量,在 x86_64/linux 上,它们将存储在特殊的内存段中,并通过 gs 段寄存器访问,该寄存器对于每个线程都设置不同。 - PlasmaHH
异常对象是临时的吗?还是完全不同的东西。(在§3.7中,标准列出了四种“存储期限”:静态、线程、自动和动态。我经常想知道这个问题:临时对象显然有不同的持续时间,异常对象也是如此。) - James Kanze
@James,即使临时变量的实际生命周期可能大大缩短,为周围块的生命周期分配完整表达式临时存储器在堆栈上并不是不合理的。这是一种简单的模型,可以实现,并且符合C++规范。12.2p5末尾的示例讨论了具有静态存储期的临时变量。不幸的是,静态存储期有时在规范中用于不打算匹配临时变量的事物(例如“引用常量表达式”的定义)。 - Johannes Schaub - litb
委员会回复了您的缺陷报告,称他们目前没有采取任何行动,因为规范中似乎没有出现临时变量具有静态或自动存储期所引起的问题(可能是因为任何“XXX存储期”提到的“变量”都不会干扰临时变量,因为临时变量不是变量)。但是,引用和地址常量表达式的定义涉及“具有静态存储期的对象”,这与临时变量匹配 - Johannes Schaub - litb

4

这高度依赖于实现,但它们可能驻留在自动存储中。

请注意,由于优化的原因,范围可能令人感到违反直觉。

以下内容:

class A
{
//...
};

//....

A foo()
{
   A a;
   return a;
}

在这里,对象 a 不一定仅存在于函数的作用域中,但是RVO可能会发生。
另外,当通过值传递一个临时对象时,它可能不会立即被销毁。
void foo(A a);
//...

foo( A() );

在这里,临时变量不一定只存在于该行中,而可以直接构造在方法的参数栈中。


0

大多数(如果不是全部)的实现都将它们存储在堆栈上(即自动存储),尽管我认为标准没有规定任何地方。像这样做肯定更容易,因为编译器必须保证临时变量的生命周期,并且可能会出现同一函数的递归调用,创建另一个临时变量实例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接