堆栈分配的对象在超出范围后仍然占用内存?

时间:2012-06-22 19:54:58

标签: c++ scope destructor

人们总是谈论如果没有new关键字创建的对象在超出范围时会被销毁,但是当我想到这一点时,似乎这是错误的。当变量超出范围时,可能会调用析构函数,但是我们怎么知道它不再占用堆栈中的空间呢?例如,请考虑以下事项:

void DoSomething()
{
  {
    My_Object obj;
    obj.DoSomethingElse();
  }
  AnotherFuncCall();
}

obj执行时,是否可以保证AnotherFuncCall不会保存在堆栈中?因为人们总是说它,所以他们说的必须有一些真理,所以我假设在obj之前AnotherFuncCall超出范围时必须调用析构函数。这是一个公平的假设吗?

8 个答案:

答案 0 :(得分:3)

你混淆了两个不同的概念。

是的,当对象的析构函数离开其封闭范围时,将调用它。这是由标准保证的。

不,不能保证语言的实现使用堆栈来实现自动存储(即,您所指的"堆栈分配的对象"。)

由于大多数编译器使用固定大小的堆栈,我甚至不确定您的问题是什么。它通常被实现为固定大小的存储器区域,其中指针移动只需要清除"清理"堆栈作为该内存将很快再次使用。

因此,由于用于实现堆栈的内存区域的大小是固定的,因此无需将对象所占用的内存设置为0或其他内容。它可以在那里生活,直到它再次被需要,没有伤害。

答案 1 :(得分:1)

我认为它取决于堆栈中对象的创建位置。如果它在底部(假设堆栈增长),那么我认为第二个函数可能会覆盖被破坏的对象空间。如果对象在堆栈内,则可能浪费了该空间,因为所有其他对象都必须被移位。

答案 2 :(得分:1)

您的堆栈未动态分配和解除分配,它就在那里。您的对象构造函数和析构函数将被调用,但您无法获取内存。

答案 3 :(得分:1)

  

因为人们总是这么说,所以他们所说的必须有一些真理,所以我假设当obj超出范围时,必须在AnotherFuncCall之前调用析构函数。这是一个公平的假设吗?

这是对的。请注意,最后一个问题没有说明堆栈“。实现是否使用堆栈或其他东西,取决于实现。

答案 4 :(得分:1)

人们说的确是如此。对象仍保留在内存位置。但是,堆栈的工作方式意味着对象从堆栈中获取任何内存空间。

在堆栈上分配内存时,通常发生的是堆栈指针 递减 sizeof(type)变量超出范围并释放对象,堆栈指针 递增,因此收缩有效大小在堆栈上分配的数据。实际上,数据仍然位于其原始地址中,已销毁或已删除

只是为了澄清一下,C ++标准对此绝对是 nothing !在内存分配方面,C ++标准完全没有意识到任何称为堆栈或堆的东西,因为它们是特定于平台的 实现细节

答案 5 :(得分:1)

在本地范围内“在堆栈上”创建的对象具有所谓的自动存储持续时间。标准说:

C ++ 03 3.7.2自动存储持续时间

  

1 /本地对象显式声明为auto或者是否注册   显式声明static或extern具有自动存储持续时间。   这些对象的存储一直持续到它们所在的块   创建退出。

     

2 / [注意:这些对象被初始化并销毁,如中所述   6.7。 ]

关于破坏这些物体:

6.7声明声明

  

2 /初始化具有自动存储持续时间(3.7.2)的变量   每次执行声明声明。变量与   在块中声明的自动存储持续时间在退出时被销毁   从块(6.6)。

因此,根据标准,当具有局部范围的对象超出范围时,将调用析构函数并释放存储。

天气与否,标准没有说存储在堆栈上。它只是说存储已经发布,无论它在哪里。

某些架构没有与PC相同的堆栈。 C ++适用于任何类型的可编程设备。这就是为什么它从来没有提到任何关于堆栈,堆等的原因。

在运行Windows和用户模式代码的典型PC类型平台上,这些自动变量存储在堆栈中。这些堆栈是固定大小的,并在线程启动时创建。当它们被实例化时,它们会占用堆栈上更多的空间,并且堆栈指针会移动。如果你分配了足够的这些变量,你将溢出堆栈,你的程序将死于丑陋的死亡。

尝试在Windows PC上运行此功能,看看示例会发生什么:

int main()
{
    int boom[10000000];
    for( int* it = &boom[0]; it != &boom[sizeof(boom)/sizeof(boom[0])]; ++it )
        *it = 42;
}

答案 6 :(得分:0)

堆栈上的局部变量不占用额外的内存。系统从每个线程的堆栈中提供一些内存,堆栈上的变量只使用它的一部分。在用完作用域之后,编译器可以将堆栈的相同部分重用于其他变量(稍后在同一函数中使用)。

答案 7 :(得分:0)

how do we know that it is no longer taking up space in the stack?

我们没有。有办法看看它们是否有,但这些是架构和ABI特定的。通常,当函数将控制权返回给调用者时,函数会弹出它们推送到堆栈的任何内容。 C / C ++保证的是当它们离开作用域时它将调用高级对象的析构函数(尽管某些较旧的C ++如MSVC 6在它们没有的时候会有可怕的错误)。

Is it guaranteed that obj will not be saved on the stack when AnotherFuncCall is executed? 

没有。只要符合ABI要求,编译器就可以决定何时以及如何推送和弹出堆栈帧。