C++,new,opeator new,malloc & delete, opeator delete, free之间的关系

首先我们来看一下operator new,因为new中调用了operator new,下面是operator new 的部分源码

typedef void (*)()  new_handler;

void *operator new(size_t n) throw(bad_alloc) {
    // corner cases...
    void *ptr = 0;
    new_handler nHandler = nullptr;
    while (true) {
        if (ptr = malloc(n)) {
            return ptr;
        } else {
            if (nHandler = get_new_handler()) {
                (*nHandler)();
            } else {
                // throw exception...
            }
        }
    }
    // ...
}

首先我们来看一下实现思路,有一个空指针ptr在循环中使用malloc开辟空间,malloc开辟不成功会返回空指针NULL,其实也就是0,申请不成功的话会去尝试扩容内存,nHandler是用来扩容,具体怎么实现,我们本篇博客为初阶探讨,不进行深入讨论,如果扩容失败,那么就会抛出异常,所以我们可以把operator new 看成 malloc的升级版,malloc只会申请失败后返回NULL,不会去做其他处理

下面我们看一下new的部分反汇编,因为我没有在VS中找到new的源码,gcc中应该会有

A* ptr1 = new A;
00736EC4  push        4  
00736EC6  call        operator new (0731154h)  
00736ECB  add         esp,4  
00736ECE  mov         dword ptr [ebp-104h],eax  
00736ED4  mov         dword ptr [ebp-4],0  
00736EDB  cmp         dword ptr [ebp-104h],0  
00736EE2  je          __$EncStackInitStart+5Dh (0736EF7h)  
00736EE4  mov         ecx,dword ptr [ebp-104h]  
00736EEA  call        A::A (07314B0h)  
....

可以看到,它压栈后首先调用了operator new,中间经过处理后(初阶,不做深入讨论),调用了A的默认构造函数,所以这就是new和opeator new的区别所在,多调用了类的构造函数

operator new 有几个重载,因为本篇博客不是主要写opeator new的,就不多介绍,或许之后会单开一篇博客去写operator new

delete 里面呢,调用了operator delete,同样,operator  delete也有几个重载一一与opeator new 相对应,operator 里面呢调用了free,看一下delete汇编代码

delete ptr1;//自定义对象 
00782A0E  mov         eax,dword ptr [ptr1]  
00782A11  mov         dword ptr [ebp-110h],eax  
00782A17  cmp         dword ptr [ebp-110h],0  
00782A1E  je          __$EncStackInitStart+0DBh (0782A35h)  
00782A20  push        1  
00782A22  mov         ecx,dword ptr [ebp-110h]  
00782A28  call        A::`scalar deleting destructor' (078137Ah)  
00782A2D  mov         dword ptr [ebp-118h],eax  
00782A33  jmp         __$EncStackInitStart+0E5h (0782A3Fh)  
00782A35  mov         dword ptr [ebp-118h],0

                 
delete ptr1;//内置类型 int         
00A71B12  mov         eax,dword ptr [ptr1]  
00A71B15  mov         dword ptr [ebp-0ECh],eax  
00A71B1B  push        4  
00A71B1D  mov         ecx,dword ptr [ebp-0ECh]  
00A71B23  push        ecx  
00A71B24  call        operator delete (0A710A0h)  
00A71B29  add         esp,8  
00A71B2C  cmp         dword ptr [ebp-0ECh],0  
00A71B33  jne         __$EncStackInitStart+0A5h (0A71B41h)  
00A71B35  mov         dword ptr [ebp-0F4h],0  
00A71B3F  jmp         __$EncStackInitStart+0B5h (0A71B51h)  
00A71B41  mov         dword ptr [ptr1],8123h  
00A71B48  mov         edx,dword ptr [ptr1]  
00A71B4B  mov         dword ptr [ebp-0F4h],edx 

这是两段完整的delete 汇编代码,可以看到他释放对象时只调用了对象的析构函数,并没有调用free or operator delete,当然也可能是编译器不同,我的测试环境为VS2022,理论上来讲他应该是像内置类型一样,先析构再调用operator delete 然后operator delete内部 再调用free,或许是编译器做了什么优化导致他并没有这么做

总结:new内部调用了operator new,operator new 调用了 malloc,并在申请内存失败时可以抛出异常,malloc仅返回NULL,new在operator之上升级了可以调用对象的构造函数,operator delete调用了free,它俩其实很相似,没什么不同,delete 在释放对象时调用析构函数,在释放内置类型指针时调用operator delete

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值