学习笔记13-C++-内存分配

来源:互联网 发布:极简网盘系统源码 编辑:程序博客网 时间:2024/05/21 22:25

malloc/free和new/delete 应用

C++有两组内存操作,分别是malloc/free和new/delete。new/delete是C++的操作符,malloc/free是C的函数。
new有两个作用:分配内存;调用类的构造函数。
delete也有两个作用:释放内存;调用类的折构函数。
而malloc和free只能分配和释放内存。
malloc/free的原型分别是:

void*malloc(size_t Size)//返回一个void类型的指针,具体使用的时候需要做类型转换。void*free(void *ptr)//参数是指针,释放该指针指向的内存。ptr=NULL//注意释放内存后应该把该指针指向NULL,防止后面再次使用这个指针。

原型很简单,但是需要注意,malloc申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息——分配块的长度,指向下一个分配块的指针等等。这意味着越界使用动态分配的存储块,尤其是越界赋值,可能引起非常严重的后果。
而new/delete是C++的保留字,可以当做一个操作符。当然也不能越界。
注意new返回的指针是有类型的。

char*p = (char*)malloc(sizeof(char)*20);p = "abcdef";free(p);p = NULL;char *b = new char[20];b = "abcdefg";delete[]b;b=NULL;

上面两个代码的功能是一样的,都是动态分配一个char数组,容量是20。
下面再看看new/delete在类构造和折构中的应用:

//虚函数可以实现多态性//折构函数可以是虚函数,构造函数不行#include<iostream>using namespace std;class A{    public:    int m=0,n=0;    virtual void func()//虚函数    {        cout<<"调用A类func函数"<<endl;    }    void func2()    {        cout<<"调用A类func2函数"<<endl;    }    //virtual void func3()=0;//纯虚函数,必须在继承类中定义    A()    {        cout<<"调用A类构造函数"<<endl;    }    A(int x,int y)    {        m=x;        n=y;        cout<<"调用A类有参构造函数"<<endl;    }    virtual ~A()//此处如果不声明为virtual,折构的时候就不会调用B的折构了,只会调用A的    {        cout<<"调用A类折构函数"<<endl;    }};class B:public A{    public:    B()    {        cout<<"调用B类构造函数"<<endl;    }    void func()    {        cout<<"调用B类func函数"<<endl;    }    void func2()    {        cout<<"调用A类func2函数"<<endl;    }    void func3()    {        cout<<"调用B类func3函数"<<endl;    }    ~B()    {        cout<<"调用B类折构函数"<<endl;    }};int main(){    A *a=new B();    a->func();//这里调用的是B类的func函数    a->func2();//这里调用的是A类的func2函数    //a->func3();//这里调用的是B类的func3函数    delete a;//此处会同时调用B和A的折构函数    cout<<endl;    A *a2=new A(3,4);    cout<<a2->m<<" "<<a2->n<<endl;    delete a2;    cout<<endl;    A a3[3];    cout<<endl;    //a3[1]=A(3,4);    cout<<a3[1].m<<" "<<a3[1].n<<endl;    return 0;}

运行上面代码可以看到,用new可以调用构造函数,但是不会自动折构,需要自己delete。
而使用传统方法定义类的话,会自动折构,不需要显式调用折构函数。

malloc/free 实现

这里参考”石锅拌饭”的博客

#include<unistd.h>#include<stdlib.h>struct memory{    int available;//1 available 0 not available    int size;}mcb;void *memstart;//where available memory startvoid *lastaddr;//where is the last available addressint hasinit;//1 has init 0 has not initvoid init(){    lastaddr=sbrk(0);//有效内存的最尾端地址为堆尾地址    memstart=lastaddr;    hasinit=1;}void *mymalloc(int num){    if(!hasinit)        init();    void *current=memstart;//current ptr    void *ret=NULL;//return ptr    num+=sizeof(mcb);//在分配的内存基础上加上内存控制块结构体mcb的大小    while(current!=lastaddr)    {        mcb *pmcb=current;//定义一个控制块结构体的指针        if(pmcb->available&&pmcb->size>=num)//如果该块内存可用且大于要求分配的内存        {            pmcb->available=0;//标记为已占用,not available            ret=current;//返回这块地址的指针            break;        }        current+=pmcb->size;//不合适就跳过这块内存    }    if(!ret)//如果没有找到可用内存块    {        sbrk(num);//调整堆的尾部大小,增加一块大小是num的内存        ret=lastaddr;//将新增的这块内存返回        lastaddr+=num;//更新lastaddr        mcb *pcb=ret;//设置这块新增加内存的控制信息        pcb->size=num;        pcb->available=0;    }    ret+=sizeof(mcb);//返回的内存块要跳过控制结构体    return ret;}void myfree(void *start){    mcb *pmcb=(mcb*)(start-sizeof(mcb));//因为之前跳过了控制结构体,减去也就是指针指向控制体    pmcb->available=1;//将控制体信息置为available即可}int main(){    char *p=(char*)mymalloc(sizeof(char)*20);    p="abcdef";    myfree(p);    p=NULL;    return 0;}