在哪里分配按值返回的对象

时间:2013-09-08 16:43:51

标签: c++ temporary-objects

问题是:在按值返回时,临时对象在哪里分配?即,在堆栈上,在动态分配的内存中 - 编译器在这种情况下做了什么?

我正在深入研究C ++ 03中移动构造函数习惯用法中的基础逻辑,如More C++ Idioms/Move Constructor中所述,有趣的部分是如何返回一个对象:

struct foo {
    int values[100];
    ...
};

foo func() {
    foo ret;
    ... // assign value to ret
    return ret;
}

int main() {
    foo a(func());
    ...
    return 0;
}

return ret;a(func)之间的点清楚地包含堆栈清理和进一步的复制构造,但临时对象在传递到复制构造函数之前存储在哪里?也许,我在搜索结果中监督了答案,但仍无法找到解释。

修改

好的,这个例子可能看起来过于简单。在实际应用中,我们可以写出类似的东西:

class Command {
public:
    Command();
    Command(const Command &);
    ...

private:
    CommandResponseType mResponseType;

    quint64    mId;
    QString    mName;
    quint16    mTypeCode;
    QDateTime  mDatetime;

    TParamList mParams;
};

这样的类不是POD,编译器可能不会通过简单地在堆栈上分配值来优化复制构造Command a(someInstanceOfOtherClass.getCommand("foo"));。至少,涉及QString,QDateTime和TParamList的复制构造。

如果我理解正确,getCommand()具有__thiscall调用约定,这使得被调用者必须自己清理堆栈。逻辑解决方案是在内存中分配结果返回指针。我将尝试不同的场景并进入装配。

3 个答案:

答案 0 :(得分:1)

一种可能性是,如果编译器足够聪明以将其优化为分配(在main()的堆栈帧内)和移动,则根本没有临时对象。如果有,那么很可能在堆栈上,但为什么不检查生成的程序集?

答案 1 :(得分:0)

当我写foo a(func());时,调用结构构造函数,它基本上是一个函数。这采用参数func()。因此代码将首先计算func()并将返回值推送到堆栈。现在foo()将此值作为参数。实现提供商可以在这里进行任何类型的优化。 请纠正我如果我错了。

答案 2 :(得分:0)

如何在堆栈上构造对象的一个​​简单示例是在非分配形式operator new中隐式使用void* operator new (std::size_t size, void* ptr) throw()

class Foo {
public:
    Foo();
    Foo(const Foo &);
    ~Foo();
private:
    // data members
    ...
}

void bar() {
    Foo f1;
    // // Allocate sufficient memory on stack:
    // char f1[sizeof(Foo)];
    // // Call operator new on this memory and execute Foo's constructor
    // // with (this == f1):
    // operator new (sizeof(Foo),f1) Foo();
    ...

    // Or «non-optimized» case, with copy-constructor involved:
    Foo f2 = Foo();
    // char f2[sizeof(Foo)];
    // {
    //     // tmp is constructed as in the previous case:
    //     char tmp[sizeof(Foo)];
    //     operator new (sizeof(Foo),tmp) Foo();
    //     // And then f2 is constructed using Foo's copy-constructor:
    //     Foo::Foo(f2 /*this*/, tmp)
    // }
    // // Here, tmp must be destructed and popped from stack.
}

链接:

http://en.wikipedia.org/wiki/Return_value_optimization