C/C++ 动态内存管理

来源:互联网 发布:云南旅游业数据统计 编辑:程序博客网 时间:2024/05/22 08:09

C/C++ 动态内存管理

C语言:

在C语言中,有三个在堆上开辟内存的函数,它们分别是
@ (C语言) [malloc,realloc,calloc]

malloc
void* malloc(size_t size); * 它返回一个void*类型的指针,在堆上开辟一个大小为size字节的一段连续空间。
realloc
void* realloc (void* ptr, size_t size);
指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。
新的大小可大可小(如果新的大小大于原内存大小,则新分配部分不会被初始化;如果新的大小小于原内存大小,可能会导致数据丢失。
calloc
在内存的动态存储区(堆)中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;并且把数据初始化为0。如果分配不成功返回NULL。

这三个函数都对应的是free( )

注意::
1:动态开辟的内存,要释放,不然会造成内存泄漏,什么是内存泄漏呢?大家可以看这篇博客

[http://blog.csdn.net/invisible_sky/article/details/78205461?locationNum=6&fps=1]

2::free(NULL)程序会崩溃;也就是说,如果free(a)。a这个指针没有指向一块动态开辟的空间,那么程序就会崩溃。

3::对一块空间free()多次,程序也会崩溃。

4::free()一块完整空间的一部分,也是不允许的,程序也会崩溃。

C++:

C++也有三个在堆上申请内存的函数:

(1):new + 类型名
例如:int * p = new int ;
(2):new + 类型名+(初始化的数)
例如:int * p = new int (0);
开辟一个大小为4个字节(int)的空间,用p来维护,并且把这段空间初始化为0;
(3):new + 类型名 + [个数]
例如:int * p = new int [10];
开辟一个大小为sizeof(int)*(10)个字节的空间,可以理解为开辟了一个类似于数组的连续空间,长度为10;

总结:
new与malloc,calloc,realloc的不同:

(1):new不需要手动计算类型大小,而其他三个需要
(2):new不需要返回的强制类型转换(默认为new后面紧跟的类型名),而其他三个则需要强制类型转换,不然编译器会报错
(3):new与delete匹配使用,其他三个与free匹配使用
(4):最重要的一点,new 一个类,它会自动调用这个类的构造函数,然后delete的时候会调用这个类的析构函数;
delete 用于释放new分配的内存,和new成对调用
free用于释放malloc分配的内存,和malloc成对调用
使用free释放时需要判断指针是否为NULL,delete不用
free释放内存,但不调用对象的析构函数
delete不仅释放内存,还调用对象的析构函数
delete和new是对对象的操作,是运算符
free和malloc是对内存空间的操作

例如:

#include <iostream>using namespace std;class AA{public:    AA(int a = 0)        :_a(new int (a))    {}    ~AA()    {        delete _a;    }private:    int *_a;};int main(){    AA* p = new AA[4];//new了AA类的四个对象    delete[] p;    return 0;}

AA* p = new AA[4];
这句可以理解p指向一个空间(这个空间是4个AA类的对象组成的连续空间)也可以理解成对象数组;但是这个空间在堆上;

要知道它会调4次拷贝构造和4次析构函数;试想编译器怎么知道需要调几次;所以请看下面:
这里写图片描述

相同点:

(1): 本质上new还是用malloc实现的;为什么这么说呢,当然是用依据的,请看下图:

new[] 去调operator new[]

这里写图片描述
operator new[] 去调operator new

这里写图片描述
operator new 去调 malloc

这里写图片描述

free一段new [] 开辟的空间,程序会崩溃
这里写图片描述

这里写图片描述

delete[] 在释放内存之前需要把指针往前移,让指针指向空间的起始位置;了解了这一点,我们就可以用free暂时替代delete的作用:

接下来,我们实现NEW_ARRAY/DELETE_ARRAY宏,模拟new[]/delete[]申请和释放数组:

要这么做,首先要清楚的了解new/delete和new[]/delete[]到底做了哪些事情?

(1):new做了两件事情:调用operator new分配空间;调用构造函数初始化对象。

(2):delete也做了两件事情:调用析构函数清理对象;调用operator delete释放空间。

(3):new[N]:调用operator new分配空间;调用N次构造函数分别初始化每个对象。

(4): delete[]:调用N次析构函数清理对象;调用operator delete释放空间。

代码实现如下::

#include <iostream>using namespace std;#define NEW_ARRAY(PTR,TYPE,N)                     \        do                                        \        {                                         \           PTR = (TYPE*)malloc(sizeof(TYPE)*N+4);//多开4个字节的空间,用来存放需要调用拷贝构造和析构的次数 \           *(int*)PTR = N;                        \           PTR= (TYPE*)((int*)PTR+1);             \           for (size_t i = 0; i < N; i++)         \               new(PTR + i)TYPE; //调拷贝构造                   \        } while (0);#define DELETE_ARRAY(PTR,TYPE)             \    do                                     \    {                                      \        size_t N = *((int*)PTR - 1);       \        for (size_t i = 0; i < N; i++)     \            PTR[i].~TYPE(); //调析构函数            \        PTR = (TYPE*)((int*)PTR-1);//把指针向前移动4个字节,指向空间的起始位置               \        free(PTR);                  \    } while (0);            class AA{public:    AA(int a = 0)        :_a(new int (a))    {}    ~AA()    {        delete _a;    }private:    int *_a;};int main(){    AA* p = NULL;    NEW_ARRAY(p,AA,4);    DELETE_ARRAY(p,AA);    return 0;}
原创粉丝点击