C++内存管理
关于堆和栈的知识点:
- 堆的空间较大,有几个G,其它区都是MB
- 堆向上使用空间,栈向下使用空间
- 每个程序运行起来都有4G虚拟内存,都是按需申请和释放。
所以堆一般不可能达4G
- 例题:
- 下面有关c++内存分配堆栈说法错误的是( ):
A.对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制
B. 对于栈来讲,生长方向是向下的,也就是向着内存地址减小的方向;对于堆来讲,它的生长方向是向上的,是向着内存地址增加的方向增长
C.对于堆来讲,频繁的 new/delete 势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题
D.一般来讲在 32 位系统下,堆内存可以达到4G的空间,但是对于栈来讲,一般都是有一定的空间大小的
-
分析:
D:因为32位下,程序使用内存最大4G,不可能都给堆。所以堆达不到4G。 -
- C++中关于堆和栈的说法,哪个是错误的:( )
A.堆的大小仅受操作系统的限制,栈的大小一般较小
B.在堆上频繁的调用new/delete容易产生内存碎片,栈没有这个问题
C.堆和栈都可以静态分配
D.堆和栈都可以动态分配
解析:
- 栈既可以自动分配也可以手动动态分配,但是栈分配到的不能用free或delete释放。所以D正确,堆栈都可以动态分配。
- 堆只能手动动态分配,不能静态分配。
- 堆上频繁用new、delete容易产生碎片,栈因为自动分配,所以不存在此问题。
变量内存区判断:
4. char* pchar3 = “abcd”;
指针指向常量字符串的地址,该指针是常量指针,有的编译器会强调加const,因为指向内容不能改变。
char char2[] = “abcd”
这个char2[] 数组,char2代表数组首地址,而char2代表的是字母a,
因为char char2[] = “abcd”左边是字符数组,字符数组都在栈上开辟,而char3是指针,右边是常量,所以两者不一样。
int ptr1 = ()malloc(),这种ptr1是临时变量,在栈,它只是指向了堆区。
而*ptr1,解引用,变为它存的地址上放置的值
sizeof:对数字数组,总共几个数字共占的大小
对字符数组,大小方面,会多一个\0结束符
strlen:专为字符串和字符数组,结果是 字母个数
再次注意:
char char2 = “abcd”
char*pchar3 = “abcd”
这两个典型的一个在栈上,一个在堆上,前者因为字符数组是临时变量,后者因为是常量。
C++动态内存管理
int* a = new int[5]
intb = new int(5)
第一行开辟5个int空间
第二行带初始化。
A p4 = new A【5】
A会自动初始化。
delete和free的区别。
delete自动调用析构。
而free之后,还得手动置0,或NULL
对于自定义类型调用析构,而内置类型不管。
资源清理:delete
delete:它自动调用析构。
【回忆:】析构函数不需要手动调用,编译器自己决定。
单纯delete解决不了自己开辟的空间归还问题。
class Test
{
private:
int* a;
public:
Test()
{
a=new int(0);//需要析构函数来delete,单纯delete Test是无法回收a内存的,直接内存泄漏
}
};
free和delete不要混着用。
new和delete应该匹配:注意括号
new就用delete
如果我使用 :A* p = new A[5]
最后要用:delete[] p;
C++要new有两个原因:
- 定义出来的对象,就一定要初始化。【就是给值】
- 抛出异常:面向对象的语言处理错误的方式一般是抛异常,且C++中求报错抛出异常
面向过程的语言处理错误的方式是:错误码
C的malloc还有什么问题:
有时候正常用也可能报错:malloc向堆申请空间,堆虽然很大,但是终究有限,所以还是会有错的可能。
而C++中new失败了会直接报错,不会返回。
可以通过捕捉错误,去输出查看是什么类型错误。比起C方便,不用做检查。
delete和free一般不会失败,如果失败都是释放空间存在越界或释放指针位置不对。
- 例题:
- 下面有关c++内存分配堆栈说法错误的是( )
A.对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制
B. 对于栈来讲,生长方向是向下的,也就是向着内存地址减小的方向;对于堆来讲,它的生长方向是向上的,是向着内存地址增加的方向增长
C.对于堆来讲,频繁的 new/delete 势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题
D.一般来讲在 32 位系统下,堆内存可以达到4G的空间,但是对于栈来讲,一般都是有一定的空间大小的
-
- 例题:
c++语言中,类ClassA的构造函数和析构函数的执行次数分别为( )
- 例题:
ClassA *pclassa=new ClassA[5];
delete pclassa;
- 解析:
- 开辟对象数组大小为几,就调用几次构造函数。
- 这是个对象数组,本该用delete[] pclassa;
而delete会调用一次析构,**且delete一般不是先free,先调用析构函数。**往往会引发程序崩溃。
new出来的对象数组,如果delete会直接崩掉。
- 析构的顺序为:
设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为? ( )
C c;
void main()
{
A*pa=new A();
B b;
static D d;
delete pa;
}
ABDC.【因为A手动执行delete,最早调用析构。】
C和D都在静态区,应按照栈顺序,A在堆上,B在临时栈区,应该最早销毁,最早用析构。
我本来疑问: new申请的空间,什么时候调用析构。
属实眼瞎了,人家下面对new出来的pa做了delete,所以delete pa先调用A的析构函数。如下图,C是全局变量,D是静态局部遍历,两者C先定义后是D,销毁按栈特点,先D析构再C析构。因为delete,所以A先做析构。析构和构造顺序相反。
CBD的构造顺序是:C、D、B,所以最后析构:B、D、C。
析构顺序完全和构造顺序相反,根据栈特点理解。
上面先构造了全局对象,再构造了局部静态对象,最后构造普通对象。其中。
4. 使用 char* p = new char[100]申请一段内存,然后使用delete p释放,有什么问题?( )
A.会有内存泄露
B.不会有内存泄露,但不建议用
C.编译就会报错,必须使用delete []p
D.编译没问题,运行会直接崩溃
这个题显然是new和delete不按匹配使用。
- A。 char是内置类型,对于内置类型delete和free作用一样,不会造成内存泄漏。
- 但是这里毕竟带[],所以建议成对。
- 以下代码中,A 的构造函数和析构函数分别执行了几次: ( )
A*pa=new A[10];
delete []pa;
申请空间不调用构造函数,构造函数调用次数是数组的大小。
例题
其中,strlen()统计的是字符数量,不统计\0,但是pChar3、char2右值都是常量,它们都以\0结尾。但是char2是个字符数组,且pChar3也是个指针变量,都在栈区存着,sizeof指针,它只求指针大小,所以必然是4,而sizeof字符数组,肯定带着\0
【回忆输出格式】:
//记住:补充位数和补充值的方法,且用头文件:
// #include
// cout << year <<“-” <<setw(2)<<setfill(‘0’) << month << “-” <<setw(2) << setfill(‘0’) << day << endl;
【补充:】此时我在听别人面试
为什么排序可以提高效率?
排序后可以减少比较次数。