自从我上次用 C++ 做一些事情以来已经很多很多年了。这些天,有人向我寻求有关 C++ 的学校项目的帮助,我对我所见过的语言的一个“功能”很感兴趣,它工作得很好,但我预计它不会工作。
我记得,我可以在堆上或堆栈上创建类的实例:
int main() {
MyClass *inHeap = new MyClass();
MyClass inStack = MyClass();
}
据我所知,第一个变量,inHeap
,将使编译器在main
栈帧中保留一些足够的栈保存一个指针(4 个字节?8 个字节?类似的东西),它指向堆中对象的实际实例。
此外,第二个变量,inStack
,将使编译器保留足够的堆栈来保存 MyClass
的完整实例main
堆栈框架。
现在,回到我的问题。假设我有一个函数应该返回 MyClass
的实例。起初,我以为它只能返回堆中的实例:
MyClass *createInHeap() {
return new MyClass();
}
int main() {
MyClass* inHeap = createInHeap();
}
但我看到的是以下内容:
MyClass createInStack() {
MyClass c = MyClass();
return c;
}
int main() {
MyClass inStack = createInStack();
}
这里到底发生了什么?
在
createInStack
的堆栈帧中是否保留了MyClass
实例的内存?如果是这种情况,当函数createInStack
返回时,这段代码是否会强制将实例复制到main
的堆栈帧?这个复制是如何执行的,即它是否只是在main
函数中自动为我调用复制构造函数?我想到的另一种可能性是编译器足够聪明,已经在
main
堆栈框架中为MyClass
实例保留了内存。这存在吗?这是某种优化以避免制作可能昂贵的拷贝吗?
作为最后一个问题,当我在堆栈中创建了一个实例时,它的析构函数究竟何时被调用?创建它的范围何时结束?
最佳答案
如果你正在做这样的事情:
MyClass createInStack()
{
MyClass return_value;
return return_value;
}
int main()
{
MyClass inStack = createInStack();
}
那么是的,c
在 createInStack()
中的堆栈上逻辑创建然后逻辑上返回它的拷贝,然后复制到 inStack
中在 main
.
有一个常见的误解,认为由于所有这些逻辑复制,按值返回效率低下。但是,由于命名返回值优化,这并不是实际发生的情况。调用函数中的构造步骤只是推迟到被调用函数。它会是这样的(伪代码):
void createInStack(MyClass &return_value)
{
return_value.MyClass(); // construct return_value (not actually valid syntax)
}
int main()
{
MyClass inStack; // except don't call the constructor
createInStack(inStack);
}
如您所见,没有实际复制发生。
此外,编译器可能会做其他优化。它甚至可能决定 inStack
从未使用过,只是没有创建它,但您可以非常确定至少命名返回值优化将避免大量复制。
关于c++ - 返回在堆中分配的实例与在堆栈中分配的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16265568/