C++之new和delete重载

首先要知道new和delete是一种运算符,而malloc和free是一种系统调用函数,因此new和delete是可以重载的。
先来举个例子看一下new与delete 和 malloc与free的区别:

class A{
public:
    A(){
        cout << "constuctor" << endl;
    }
    ~A(){
        cout << "distuctor" << endl;
    }
};

int main()
{
    A *a = new A;
    delete a;
    cout << "--------------------" << endl;
    A *b = (A*)malloc(sizeof(A));
    free(b);
    return 0;
}

这里写图片描述
很明显的可以看出new和delete会分别自动调用构造器和析构器,而malloc和free则不会。

一、new 和delete重载

new和delete既可以作为全局函数重载,也可以作为局部成员函数重载。先看全局函数重载:

class A{
public:
    A(){
        cout << "constuctor" << endl;
    }
    ~A(){
        cout << "distuctor" << endl;
    }
    int data;
};

void* operator new(size_t size){
    cout << "size = " << size << endl;
    cout << "void* operator new(size_t size)" << endl;
    void *p = malloc(size);
    return p;
}

void operator delete(void* p){
    cout << "void operator delete(A* p)" << endl;
    free(p);
}

int main()
{
    A *a = new A;
    delete a;
    return 0;
}

输出结果:
这里写图片描述

首先在A类中加入了一个int型的数据成员,那么sizeof(A) = 4, 这里对new的重载函数的参数中有个size_t类型,这实际是个unsigned int类型, size就是用来表示需要分配的空间大小,内部的机制会知道应该分配4个字节的空间给类A的对象,至于是如何知道的,这个就对我们隐蔽了(所以对new的重载并不是真正的重载,内部的东西我们还是不知道的),通过对new和delete的重载也可以发现其实函数体中就是利用malloc和free去实现的。
现在加入一个double型的指针:

int main()
{
    A *a = new A;
    delete a;
    double *p = new double;
    delete p;
    return 0;
}

结果是这样的:
这里写图片描述
可以看到就算new一个double也是用的我们重载的new和delete,这就是全局函数重载的覆盖性,特别的广,只要用到new和delete全是从全局函数去操作,因为影响范围太广,所以一般不建议这么做,那么就要进行局部成员函数重载。像这样:

class A{
public:
    A(){
        cout << "constuctor" << endl;
    }
    ~A(){
        cout << "distuctor" << endl;
    }
    void* operator new(size_t size){
        cout << "size = " << size << endl;
        cout << "void* operator new(size_t size)" << endl;
        void *p = malloc(size);
        return p;
    }

    void operator delete(void* p){
        cout << "void operator delete(A* p)" << endl;
        free(p);
    }
    int data;
};



int main()
{
    A *a = new A;
    delete a;
    double *p = new double;
    delete p;
    return 0;
}

把重载函数放到类中,当成成员函数,运行结果就是这样的:
这里写图片描述

可以看到这样就不会影响到其他类型的new和delete了。

一、new[] 和delete[]重载

new[]和delete[]与new和delete的重载很相似,只不过多了个[]而已,这里直接用局部的,全局的就不再举例了:

class A{
public:
    A(){
        cout << "constuctor" << endl;
    }
    ~A(){
        cout << "distuctor" << endl;
    }
    void* operator new(size_t size){
        cout << "size = " << size << endl;
        cout << "void* operator new(size_t size)" << endl;
        void *p = malloc(size);
        return p;
    }

    void operator delete(void* p){
        cout << "void operator delete(A* p)" << endl;
        free(p);
    }
    void* operator new[](size_t size){
        cout << "size = " << size << endl;
        cout << "void* operator new(size_t size)" << endl;
        void *p = malloc(size);
        return p;
    }

    void operator delete[](void* p){
        cout << "void operator delete(A* p)" << endl;
        free(p);
    }
    int data;
};



int main()
{
    A *a = new A[5];
    delete []a;
    double *p = new double[5];
    delete []p;
    return 0;
}

运行结果:
这里写图片描述
可以看到构造了5次,也析构了五次,重点要说的是为什么这里的size = 24, 却不是20呢。这还得从malloc说起:

char *p = (char*)malloc(100);
free(p);

这里为p开辟了100字节的空间,然后释放,只通过free(p)系统怎么知道应该释放多少空间呢,其实底层,在为p开辟空间的时候既存储了p,也存储了100这是值,那么在释放的时候就知道对p释放100空间了。new[]这个地方也是一样的,不仅存储了本身开辟的空间,同时也存储了一个指针,所以size = (4 * 5) + 4 = 24字节。

三、new重载的优点

new重载有个特别有优势的地方,我们知道类的数据成员一般都是最先在构造器中初始化的,用new重载之后,可以把数据成员的舒适化放在new中,比构造器中的初始化还早,还是使用上面的例子,这里只单独给出new的重载:

void* operator new(size_t size){
        cout << "size = " << size << endl;
        cout << "void* operator new(size_t size)" << endl;
        void *p = malloc(size);
        memset(p, 0, size);
        ((A*)p)->data = 100;    //数据成员的初始化
        return p;
    }
    int main()
{
    A *a = new A;
    cout << a->data << endl;
    delete a;
    return 0;
}

结果是这样的
这里写图片描述
可以看到数据成员的的确确被初始化了。

四、总结

最后再总结一下重载格式:

void* operator new(size_t size);
void* operator new[](size_t size);
void operator delete(类名* 对象名);
void operator delete[](类名* 对象名);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值