函数调用中创建的临时变量何时被销毁?

27

如果在函数调用的参数中创建了一个临时变量,即使这个临时变量没有直接传递给函数,它也能保证在函数结束之前一直存在吗?

可能上面的描述不太清晰,以下是一个例子:

class A {
public:
    A(int x) : x(x) {printf("Constructed A(%d)\n", x);}
    ~A() {printf("Destroyed A\n");}

    int x;
    int* y() {return &x;}
};

void foo(int* bar) {
    printf("foo(): %d\n", *bar);
}

int main(int argc, char** argv) {
    foo(A(4).y());
}

如果A(4)直接被传递给foo,它肯定不会在foo调用结束之前被销毁,但是我正在调用临时对象上的方法并失去对它的任何引用。我的本能反应是,临时对象A将在foo开始之前被销毁,但是使用GCC 4.3.4进行测试显示它并没有被销毁;输出结果为:

 

构造A(4)
  foo(): 4
  销毁A

问题是,GCC的行为是否由规范保证?还是编译器可以在调用foo之前销毁临时对象A,从而使我使用的成员指针无效?

4个回答

24

临时对象存在于创建它们的完整表达式结束之前。

在你的例子中,由 A(4) 创建的 A 对象将至少存在于表达式结束后的从调用 foo() 返回之后。

这种行为是语言标准保证的:

临时对象在包含它们创建点的(词法上)最近表达式(1.9)求值完成后被销毁。即使此评估以抛出异常结束,这也是正确的(C++03 §12.2/3)。

通过将引用绑定到临时对象可以扩展其生命周期(在这种情况下,其生命周期将延长至引用的生命周期结束),或者通过将其用作构造函数初始化列表中的初始化器来扩展其生命周期(在这种情况下,其生命周期将延长至正在构建的对象完全构建之前)。


太棒了。感谢你和杰瑞在规范中找到了参考,我找了很久都没找到。 - Michael Mrozek

6

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

也就是说,在foo返回之后,A对象不得被销毁,您是安全的。


2
临时变量的持续时间直到它所属的表达式结束 - 在本例中是函数调用。

-2

您的临时对象A(4)的生命周期足够长,可以调用y()

y()返回的内存不可靠,取决于线程和分配情况,它可能会被重新分配并在调用foo()之前更改其值。


嗯,显然 MSVC 给了我一个非标准的响应,学习标准是好事。 - Greg Domjan

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