人们总是谈论如果没有new
关键字创建的对象在超出范围时会被销毁,但是当我想到这一点时,似乎这是错误的。当变量超出范围时,可能会调用析构函数,但是我们怎么知道它不再占用堆栈中的空间呢?例如,请考虑以下事项:
void DoSomething()
{
{
My_Object obj;
obj.DoSomethingElse();
}
AnotherFuncCall();
}
当obj
执行时,是否可以保证AnotherFuncCall
不会保存在堆栈中?因为人们总是说它,所以他们说的必须有一些真理,所以我假设在obj
之前AnotherFuncCall
超出范围时必须调用析构函数。这是一个公平的假设吗?
答案 0 :(得分:3)
你混淆了两个不同的概念。
是的,当对象的析构函数离开其封闭范围时,将调用它。这是由标准保证的。
不,不能保证语言的实现使用堆栈来实现自动存储(即,您所指的"堆栈分配的对象"。)
由于大多数编译器使用固定大小的堆栈,我甚至不确定您的问题是什么。它通常被实现为固定大小的存储器区域,其中指针移动只需要清除"清理"堆栈作为该内存将很快再次使用。
因此,由于用于实现堆栈的内存区域的大小是固定的,因此无需将对象所占用的内存设置为0或其他内容。它可以在那里生活,直到它再次被需要,没有伤害。
答案 1 :(得分:1)
我认为它取决于堆栈中对象的创建位置。如果它在底部(假设堆栈增长),那么我认为第二个函数可能会覆盖被破坏的对象空间。如果对象在堆栈内,则可能浪费了该空间,因为所有其他对象都必须被移位。
答案 2 :(得分:1)
您的堆栈未动态分配和解除分配,它就在那里。您的对象构造函数和析构函数将被调用,但您无法获取内存。
答案 3 :(得分:1)
因为人们总是这么说,所以他们所说的必须有一些真理,所以我假设当obj超出范围时,必须在AnotherFuncCall之前调用析构函数。这是一个公平的假设吗?
这是对的。请注意,最后一个问题没有说明堆栈“。实现是否使用堆栈或其他东西,取决于实现。
答案 4 :(得分:1)
人们说的确是如此。对象仍保留在内存位置。但是,堆栈的工作方式意味着对象不从堆栈中获取任何内存空间。
在堆栈上分配内存时,通常发生的是堆栈指针 递减 sizeof(type)
变量超出范围并释放对象,堆栈指针 递增,因此收缩有效大小在堆栈上分配的数据。实际上,数据仍然位于其原始地址中,不已销毁或已删除。
只是为了澄清一下,C ++标准对此绝对是 nothing !在内存分配方面,C ++标准完全没有意识到任何称为堆栈或堆的东西,因为它们是特定于平台的 实现细节。
答案 5 :(得分:1)
在本地范围内“在堆栈上”创建的对象具有所谓的自动存储持续时间。标准说:
1 /本地对象显式声明为auto或者是否注册 显式声明static或extern具有自动存储持续时间。 这些对象的存储一直持续到它们所在的块 创建退出。
2 / [注意:这些对象被初始化并销毁,如中所述 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要求,编译器就可以决定何时以及如何推送和弹出堆栈帧。