c++ - 返回在堆中分配的实例与在堆栈中分配的实例

标签 c++ heap-memory allocation stack-memory

自从我上次用 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();
}

那么是的,ccreateInStack() 中的堆栈上逻辑创建然后逻辑上返回它的拷贝,然后复制到 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/

相关文章:

c++ - libpqxx:连接进程终止后如何重新连接到 Postgresql 数据库

c# - linux下C++中Gmap.Net的替代品

c++编译器错误多个变量定义

c - 链表的头节点被传递给另一个函数,它被分配给函数中的本地节点。为什么没有错误?

android - 事件和位图中的预分配

c - 我分配内存错误吗?

c++ - 将 Objective-C 应用程序链接到 C++ 静态库

malloc 内存中的 C 函数代码

c++ - 可以在堆上创建的对象在 C++ 中被视为 'being on stack' 吗?

python - 在 python 中跟踪对象分配