问题是:在按值返回时,临时对象在哪里分配?即,在堆栈上,在动态分配的内存中 - 编译器在这种情况下做了什么?
我正在深入研究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
调用约定,这使得被调用者必须自己清理堆栈。逻辑解决方案是在内存中分配结果返回指针。我将尝试不同的场景并进入装配。
答案 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.
}
链接: