C/C++动态内存管理
C语言动态内存管理
申请内存的方式
栈上(静态内存管理)
1.生命周期随栈帧。栈帧结束,内存归还给操作系统,无需程序猿管理。
2.空间开辟的大小固定,申请数组时数组的大小必须指定。他内存在编译时期就已经分配好。
3.程序在运行时期不能进行内存申请。而这种情况在编程中又很常见。所以就需要动态内存管理。
堆上(动态内存管理)
1.生命周期由程序猿管理。需要手动申请手动释放。且必须释放,否则就会造成内存泄露
2.开辟空间大小由程序猿指定,更灵活。空间分配在程序运行期间分配。
对比:栈上申请内存比较省心,规规矩矩。缺乏灵活性,而堆上申请内存更为灵活。但是灵活也就意味着风险。如果只申请,不释放,就会造成内存泄露。释放的内存的申请的内存要匹配。
int *p = (int *)malloc(20*sizeof(int)); int *pp = (int *)calloc(20, sizeof(int)); int i; printf("malloc申请的空间值: "); for ( i=0 ; i < 20; i++) { printf("%d ", *p++); } printf(" "); printf("calloc申请的空间的值: "); for ( i=0 ; i < 20; i++) { printf("%d ", *pp++); } free(p); free(pp);
class Array { public: Array(size_t size=10) :_size(size) ,_a(0) { cout<<"Array(size_t size)"<<endl; if(size>0) { _a=new int[size]; } } ~Array() { cout<<"~Array()"<<endl; if(_a) { delete[]_a; _a=0; _size=0; } } private: int * _a; size_t _size; }; int main() { Array* p1=new Array; delete p1; Array* p2=new Array[5]; delete []p2; return 0; }
C++杂谈 为什么需要虚析构函数
①虚函数:在类的成员函数前面加virtual关键字的函数;
一般把虚函数定义在public区,方便在主函数中调用
如果一个类有一个虚函数,则该类就有一个虚函数列表,所有该类的对象都共享这个虚函数表;(QT调试过程中显示的是vptr)
如果一个类有一个或者一个以上的虚函数,则该类有且只有一张虚函数表,每个类都只有一个虚函数表,该类的所有对象都共享这张虚函数表
子类的虚函数表中子类的虚函数覆盖父类的虚函数的情况,当子类将父类的虚函数override时,就覆盖了父类的虚函数;
满足override的条件:函数名相同,函数的返回值相同,形参列表相同;
纯虚函数:形式为 virtual void fun1() = 0;
纯虚函数不需要实现,原因是不会被调用到;
抽象基类:至少有一个纯虚函数的类;
抽象基类不能产生该类的对象,但可以有该类的指针或引用;
在子类中必须将父类的纯虚函数实现,不然该子类也是抽象基类;
②当一个类有子类时,该类的析构函数必须是虚函数,原因:会有资源释放不完全的情况;
对象销毁时只调用了父类的析构函数。如果这时子类的析构函数中有关于内存释放的操作,将会造成内存泄露。所以需要给父类的析构函数加上virtual。
③刚开始的时候对于这个问题我一直搞不明白,总觉得这是多此一举,后来上网查资料看到了一些人的解释明白了为什么要这样,用一个例子来解释应该最好理解了:
你写了一个飞机游戏,画面里出现什么类型飞机是随机决定的,你的代码里也就不可能用一个具体飞机类型来操作。 所以,往往是随机生成各种类型飞机,他们有共同的父类,你的代码就可以用父类指针来控制行为。比如中弹后的能量损失多少之类,每种飞机可能不同。