【问题标题】:When are temporaries created as part of a function call destroyed?作为函数调用的一部分创建的临时对象何时被销毁?
【发布时间】:2011-03-03 17:52:58
【问题描述】:

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

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

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,从而使指向我正在使用的成员的指针无效?

【问题讨论】:

    标签: c++ memory-management specifications


    【解决方案1】:

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

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

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

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

    可以通过绑定对它的引用来延长临时对象的生命周期(在这种情况下,它的生命周期会延长到引用的生命周期结束),或者通过将它用作构造函数的初始值设定项列表中的初始值设定项(在在这种情况下,它的生命周期会延长,直到正在构造的对象完全构造)。

    【讨论】:

    • 太棒了。感谢您和 Jerry 在规范中找到参考,我很难找到它
    【解决方案2】:

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

    IOW,你很安全——在foo 返回之前,不得销毁A 对象。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        • 嗯,显然 MSVC 给了我一个非标准的响应,学习标准很好。
        猜你喜欢
        • 2019-08-19
        • 2014-02-07
        • 1970-01-01
        • 2012-03-03
        • 1970-01-01
        • 2019-07-27
        • 2015-12-11
        • 1970-01-01
        • 2012-04-24
        相关资源
        最近更新 更多