什么时候创建作为函数调用的一部分被销毁?

时间:2010-06-14 21:58:08

标签: c++ memory-management specifications

作为函数调用的参数的一部分创建的临时函数是否保证在被调用函数结束之前保持不变,即使临时函数没有直接传递给函数?

几乎没有连贯的机会,所以这是一个例子:

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的行为是否符合规范?或者是否允许编译器在调用A之前销毁临时foo,从而无效指向我正在使用的成员的指针?

4 个答案:

答案 0 :(得分:20)

临时对象一直存在,直到创建它们的完整表达式结束。

在您的示例中,A创建的A(4)对象将至少存在 ,直到表达式从调用返回foo()后结束。

语言标准保证了这种行为:

  

临时对象作为评估全表达式(1.9)的最后一步被销毁,该表达式(词法上)包含创建它们的点。即使该评估以抛出异常结束,也是如此(C ++03§12.2/ 3)。

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

答案 1 :(得分:6)

§12.2/ 3:“作为评估全表达式(1.9)的最后一步,临时对象被销毁,(词法上)包含创建它们的点。”

IOW,你是安全的 - A对象在foo返回之前不得销毁。

答案 2 :(得分:2)

临时表持续到它所属的表达式的结尾 - 在这种情况下是一个函数调用。

答案 3 :(得分:-2)

临时对象A(4)的生命周期将持续足够长的时间来调用y()

y()返回时指向的内存不可靠,具体取决于可能重新分配的线程和分配,并且在调用foo()之前更改了值。