栈内存是编译时可以确定的内存,对内存是运行时动态申请的内存。
仅此而已,
A a; //在栈中分配内存(在栈上一个变量a指向堆中的一个A类型的对象(没有赋值的话是null吧?好久没写c++了不清楚))
A * a = new A(); //动态内存分配,在堆上(在栈上一个指针变量a,指向在堆上的一个A类型的对象)
对象是不会在栈上的吧,对象只会在堆里,只有基础类型的变量才会在栈上,.net是这样的,C++不清楚了
你说:“A a; //在栈上一个变量a指向堆中的一个A类型的对象”,应该不是吧?如果这样,那和A * a = new A();有什么差别呢?它如何做到自动回收内存呢?如果两个都是这么分配内存,那c++为什么不干脆都支持自动回收内存呢?
@Patrickz10: 在c++里A a;这时候a不会为null吗?不记得了
主要问题还是在于作用域,栈里的内存是在当前栈里的,一处当前栈就没了。
堆里的内存,你不去释放他,他就一直在那里
@吴瑞祥: A a;a会调用默认构造函数,当然不会为null了,只有指针才可能为null啊
你的理解有些偏差,学习下这篇文章:http://blog.163.com/dingmz_frcmyblog/blog/static/21730402320137994451342/,加深对内存分配的理解(注意 alloca 这个函数,它实际上是在栈上分配空间)。
1、栈的大小是有限制的,可以修改;
2、分配在堆上,还是分配在栈上,要综合考虑你的程序的需求;
学到了
我想先了解最基本的语法c++是如何分配内存,然后才了解alloca等那些函数或具体平台如何做啊,不知道我写的
A a; //在栈中分配内存
A * a = new A(); //动态内存分配,在堆上
这两句话对不对哦?
@Patrickz10: 第一个语句没问题,第二个语句有问题,因为 new 是个操作符语法,可以重载,然后通过调用 alloca 来在栈上分配。
@Launcher: 哦,对,我的new是没有重载的。我想知道一个问题,如果有一个自定义类型中有一个成员:vector<string> v1;那么v1是放在栈上的吗?如果v1很大,那是不是成为程序潜在的问题了?
@Patrickz10: 你最好多写点字把问题讲清楚,比如:
class A {
private:
vector<string> v1;
};
A a; // v1 分配在栈上,但是不保证 vector 或 string 的内部容器分配在栈上。
A * a = new A; // v1 分配在堆上,假定没重载 new 操作符。
A * a = (A *)malloc(sizeof(A)); // v1 分配在堆上。
@Launcher: “不保证 vector 或 string 的内部容器分配在栈上”,你意思是不是说,虽然我没有用new申请内存空间,但是c++仍然可以会自主决定要将我的对象放到栈上还是堆上,是吗?
@Patrickz10: 不是由 C++ 来自主决定的,一切取决于你的代码。比如:
class A {
public :
A(){ p = malloc(1000);}
private:
void * p;
};
A a; // a 分配在栈上,变量 p 也分配在栈上,但是 p 指向的内存空间分配在堆上。
@Launcher: class A {
private:
vector<string> v1;
};
A *getA()
{
A * a = new A; // 没重载 new 操作符的。
return a;
}
int main()
{
A *b = getA();
//use b
return 0;
}
那按上面代码,指针变量a和类成员v1应该在栈上,而a指向的对象在堆上,当我调用完getA函数之后,函数的栈空间会自动回收,那么获取的对象指针所指的对象的成员不就指向无意义的内存空间(已被回收的栈空间)了吗?
@Patrickz10: 分配在栈上的是变量 a,而不是 a 指向的内存空间(new A),因此只要不调用 delete 操作,已分配的内存空间始终有效。
@Patrickz10: 鉴于你的基础知识薄弱,你需要先找本 C 语言的书看下,把变量、指针的概念搞清楚了。
@Launcher: 我就是在弄清这些概念才会有这些疑问啊,但我想你还没有理解我的问题,我是迷惑,上面代码v1应该在栈上,是不是?但是“a 指向的内存空间(new A)”却在堆上,这按书中的说法是确切无疑的,对不对?
@Patrickz10: 但是问题却来了,当我调用完getA函数之后,函数的栈空间会自动回收,那么获取的对象指针(即b)所指的对象的成员v1就指向无意义的内存空间(已被回收的栈空间)了,这按书中的说法也是确切无疑的推论,是吧?
@Launcher: 可是实际不是,写一个测试程序就知道了,应该按这个内存分配思路,下面程序应该会报错,可是事实却能正常运行
#include <string>
#include <vector>
using namespace std;
class A {
public:
A(void) :v1(10) {v1[0]="abc";}
vector<string> v1;
};
A *getA()
{
A * a = new A; // 没重载 new 操作符的。
return a;
}
int main()
{
A *b = getA();
string v1("ABCDEFHIMDI");
printf(b->v1[0].data());
if(b->v1.size()==10) printf(":ok");
return 0;
}
程序正常的输出abc:ok
@Patrickz10: 以 32 程序描述:
A *getA()
{
// a 变量分配在栈上,假设地址(&a)为 0x0036fd6c,此地址开始的连续 4 个字节不能再分配。
// new A 分配在堆上,假设首地址为 0x00381438;
// 将 0x00381438 赋给 a,也就是首地址为 0x0036fd6c 的连续 4 个字节存放的是 0x00381438 这个整数。
A * a = new A;
// 将首地址为 0x0036fd6c 的连续 4个字节存放的数据(整数 0x00381438)写入 EAX 寄存器 .
return a;
}
// 函数调用完成,现在开始自动清理为执行此函数分配在栈上的空间,在我们这里,原先为存储 a 使用的首地址为 0x0036fd6c 的连续 4个字节可以被再次分配。
// b 变量分配在栈上,假设地址(&b)为 0x0036fe8c,此地址开始的连续 4 个字节不能再分配。
// 调用 getA
// 从 EAX 读取整数 0x00381438,将其赋值给 b,也就是首地址为 0x0036fe8c 的连续 4 个字节存放的是 0x00381438 这个整数。
A *b = getA();
从这个稍微简单点的描述中我们可以看到,函数的栈空间会自动回收,获取的对象指针并没有指向无意义的空间,为什么呢,因为我们并没有对分配在堆上的首地址为 0x00381438 的空间做任何回收操作。那么你在这里理解的错误之处,就是对指针的概念模糊,return a,返回的不是 a 这个变量,而是 &a(0x0036fd6c) 中存储的整数值 (0x00381438),a 分配在栈上,会自动回收,但是 a 中保存的值(0x00381438)是分配在堆上的内存的首地址,那么不会自动回收。
如果仅仅看你写的代码,可以修改成这样,也是正确的:
int getA()
{
A * a =new A;
return (int)a;
}
或者这样:
int getA()
{
A * a =new A;
int n = 0;
memcpy(&n, &a, sizeof(A*));
return n;
}
A *b = (A *)getA();
C++:在堆上创建对象,还是在栈上? | DevBean's World
http://www.devbean.net/2014/02/cpp-create-object-on-heap-or-stack/
并不是说指针指向的对象都是在堆上创建的。下面的代码则使用指针指向一个在栈上创建的对象:
Object obj;
Object *pObj = &obj;