我试图理解堆栈和堆内存之间的区别,并且SO上的this question以及this explanation做得很漂亮很好地解释了基础知识。
然而,在第二个解释中,我遇到了一个我有一个具体问题的例子,例子如下:
有人解释说对象m
是在堆上分配的,我只是想知道这是不是完整的故事。根据我的理解,对象本身确实是在堆上分配的,因为new
关键字已用于其实例化。
但是,指向对象m
的指针是否在堆栈上分配的同一时间?否则,如何访问对象本身,当然它位于堆中。我觉得为了完整起见,本教程中应该提到这一点,留下它会给我带来一些混乱,所以我希望有人能够清楚地告诉我,我对我的理解是正确的基本上应该有两个陈述:
1。指向对象m
的指针已在堆栈上分配
2。对象m
本身(因此它携带的数据以及对其方法的访问权限)已在堆上分配
答案 0 :(得分:17)
您的理解可能是正确的,但陈述是错误的:
已经在堆栈上分配了指向对象
m
的指针。
m
是指针。它在堆栈上。也许你的意思是指向Member
对象的指针。
对象
m
本身(它携带的数据以及对其方法的访问权限)已在堆上分配。
正确就是说 m
指向的对象是在堆上创建的
通常,在堆栈上创建任何函数/方法本地对象和函数参数。由于m
是函数本地对象,因此它位于堆栈上,但m
指向的对象位于堆上。
答案 1 :(得分:14)
"堆"和"堆"通用编程术语。特别是,不需要通过堆栈或堆数据结构在内部管理存储。
C ++具有以下存储类
粗略地说, dynamic 对应于" heap",而自动对应于" stack"。
转到你的问题:可以在这四个存储类中的任何一个中创建指针;和指向的对象也可以在任何这些存储类中。一些例子:
void func()
{
int *p = new int; // automatic pointer to dynamic object
int q; // automatic object
int *r = &q; // automatic pointer to automatic object
static int *s = p; // static pointer to dynamic object
static int *s = r; // static pointer to automatic object (bad idea)
thread_local int **t = &s; // thread pointer to static object
}
在没有说明符的情况下声明的命名变量在函数中是自动,否则是 static 。
答案 2 :(得分:5)
在函数中声明变量时,它总是在堆栈上。因此,您的变量Member* m
将在堆栈上创建。请注意,m
本身只是一个指针;它并没有指向任何东西。您可以使用它指向堆栈或堆上的对象,或者根本不指向任何内容。
声明类或结构中的变量是不同的 - 那些实例化类或结构的地方。
要在堆上创建内容,请使用new
或std::malloc
(或其变体)。在您的示例中,使用new
在堆上创建对象,并将其地址分配给m
。需要释放堆上的对象以避免内存泄漏。如果使用new
分配,则需要使用delete
;如果使用std::malloc
分配,则需要使用std::free
。更好的方法通常是使用"智能指针",这是一个包含指针的对象,并有一个析构函数可以释放它。
答案 3 :(得分:2)
是的,指针在堆栈上分配,但指针指向的对象在堆上分配。你是对的。
但是,指向对象m的指针不是同时发生的 在堆栈上分配?
我想你的意思是Member
对象。指针在堆栈上分配,并在函数(或其范围)的整个持续时间内持续存在。之后,代码可能仍然有效:
#include <iostream>
using namespace std;
struct Object {
int somedata;
};
Object** globalPtrToPtr; // This is into another area called
// "data segment", could be heap or stack
void function() {
Object* pointerOnTheStack = new Object;
globalPtrToPtr = &pointerOnTheStack;
cout << "*globalPtrToPtr = " << *globalPtrToPtr << endl;
} // pointerOnTheStack is NO LONGER valid after the function exits
int main() {
// This can give an access violation,
// a different value after the pointer destruction
// or even the same value as before, randomly - Undefined Behavior
cout << "*globalPtrToPtr = " << *globalPtrToPtr << endl;
return 0;
}
上面的代码存储了驻留在堆栈上的指针的地址(并且因为它没有Object
分配的内存delete
而泄漏内存。“ / p>
由于在退出函数后,指针被&#34;销毁&#34; (即,它的内存可以用于程序中的任何内容),您无法再安全地访问它。
上述程序可以:正常运行,崩溃或给您不同的结果。访问释放或取消分配的内存称为未定义的行为。