C/C++ 动态内存管理

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值