1

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

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

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调用约定,它要求被调用者自己清理堆栈。逻辑解决方案是将结果分配到内存中并返回一个指针。我将尝试不同的场景并查看组装情况。

4

3 回答 3

1

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

于 2013-09-08T16:45:51.977 回答
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

于 2013-09-22T12:35:31.670 回答
0

当我编写foo a(func());结构构造函数时,它被调用,它基本上是一个函数。这需要论证func()。所以代码将首先计算func()并将返回值压入堆栈。现在foo()将把这个值作为参数。实现提供者可以在这里自由地进行任何类型的优化。如果我错了,请纠正我。

于 2013-09-08T16:54:06.750 回答