临时对象什么时候销毁?

问题描述 投票:0回答:5

以下代码打印

one
two
three
。所有 C++ 编译器都希望如此吗?

#include <iostream>

struct Foo
{
    const char* m_name;

    ~Foo() { std::cout << m_name << '\n'; }
};

int main()
{
    Foo foo{"three"};
    Foo{"one"};   // unnamed object
    std::cout << "two" << '\n';
}
c++ scope destructor temporary-objects
5个回答
45
投票

临时变量一直存在,直到创建它的完整表达式结束为止。您的变量以分号结束。

这是在 [class.temporary] p4:

临时对象在评估(词法上)包含它们创建点的完整表达式的最后一步被销毁。

您的行为得到保证。

如果满足两个条件,将延长临时材料的使用寿命。第一个是当它是对象的初始值设定项时。第二个是引用绑定到临时对象时。


15
投票

管理临时对象生命周期的规则与范围的概念无关。范围是name的属性,临时对象没有名称。换句话说,临时对象没有作用域。

大多数情况下,临时对象的生命周期在创建该对象的完整表达式结束时结束,这就是您在实验中观察到的情况。这是一般规则,但也有一些例外。主要的一点是,如果您立即将引用附加到临时对象,则该对象的生命周期将延长以匹配引用的生命周期

const Foo &rfoo = Foo("one");

只要

rfoo
存在,上述临时对象就会存在。


6
投票

像这样的临时对象的范围只有一行。想一想,行结束后你就不能再引用它了,那为什么这个对象还会残留下来呢?

如果不是这种情况,编译器将无法优化函数调用中的临时对象。


4
投票

是的,这是需要的。

Foo foo("three")
创建一个普通对象,当作用域结束时该对象将被销毁。

Foo("one")
创建一个临时对象,该对象在指令结束时被销毁[1]。为什么?因为指令结束后您将无法访问它。

[1] 刻意简化:我应该说序列点


2
投票

因为标准委员会犯了错误。它这样做是因为他们选择让它这样做。它被定义为这样做。它应该被视为一个匿名实例,其作用域与已命名的实例相同。从实例化点到块的末尾。显然他们认为唯一的用途是将临时数据传递到函数中,在函数调用结束时将其压入堆栈并从堆栈中弹出......

未命名的对象仍应被推入堆栈并保留在堆栈上直到块结束,从而在预期时将其从堆栈中弹出。在单个语句中构造和销毁对象是没有意义的。我希望看到一个实际有用的实例/案例。如果它在块的持续时间内没有保留在范围内,那么它肯定是一个错误,并且至少应该生成一个警告。

© www.soinside.com 2019 - 2024. All rights reserved.