zoukankan      html  css  js  c++  java
  • 你真的了解new操作符吗

    如果你能回答出以下几个问题,请跳过本博客,以免浪费你的时间

    1new操作符能重载吗?

    2new操作符可以在一个指定内存处开僻空间不?

    3new操作符的底层实现究竟是什么样的?

    对于第一个问题不作过多解释,new是一个操作符,而且是一个可以重载的操作符,C++中不能重载的操作符最为典型的有四种(.::.*?:)

    对于23两个问题以实现源码作为剖析

    一个简单的例子

    #include<iostream>
    using namespace std;
    int main()
    {
    	int *tmp=new int(2);
    	cout<<*tmp<<endl;
    	char buf[20];
    	int *bfT=new (buf)int(5);
    	cout<<*bfT<<endl;
    	return 0;
    }
    

    注解:int *tmp=new int(2)表示的是开设一个int空间,同时tmp指向它,*bfT=new (buf)int(5)表示的是在当前存储空间buf中取出4Bytes作为一个整形变量,并将其地址赋给bfT,因此此条语句执行后,实际上在内存中并未分配空间,内存池就是基于此实现的:)

    跟踪代码,进入其汇编语言实现,可以发现如下调用:

    5:        int *tmp=new int(2);
    00401578   push        4
    0040157A   call        operator new (004205e0)
    

    从这里我们可以发现了new操作符实际上调用的是底层的operator new,前面的operator这个关键字,也说明了new操作符是可以重载的。如果有兴趣,可以继续对其进行跟踪后,可以发现operator new又调用了更底层的C语言函数malloc. 

    在C++的安装目录中,可以找到new或者new.h文件,打开它,可以找到真正需要的operator new函数,其部份源码:

    		// new AND delete DECLARATIONS
    void __cdecl operator delete(void *) _THROW0();
    void *__cdecl operator new(size_t) _THROW1(std::bad_alloc);//方式一
    void *__cdecl operator new(size_t, const std::nothrow_t&)_THROW0();//方式一
    
    #ifndef __PLACEMENT_NEW_INLINE
    #define __PLACEMENT_NEW_INLINE
    inline void *__cdecl operator new(size_t, void *_P)//方式二
    	{return (_P); }
    #if     _MSC_VER >= 1200
    inline void __cdecl operator delete(void *, void *)
    	{return; }
    #endif
    #endif

    从上面的源码中,可以看出operator new实际上有两种形式,一种是直接从内存空间中分配内存的方式一( int *tmp=new int(2)),另一种是方式二,placement new(*bfT=new (buf)int(5)),方式一中的_THROW1与_THROW0是两上宏定义

    nothrow是一个空结构体,如下定义:

    struct nothrow_t {};

    从源码中可以发现的是 placement new 只返回内存地址,而忽略了 size_t 参数,其结果是允许用户把一个对像放到一个特定的地方,达到调用构造函数的目的。

    至于为什么可以对申请的空间赋一初值,可以跳入汇编,发现如下结果

    00401578   push        4
    0040157A   call        operator new (004205e0)
    0040157F   add         esp,4
    00401582   mov         dword ptr [ebp-20h],eax
    00401585   cmp         dword ptr [ebp-20h],0
    00401589   je          main+3Ch (0040159c)
    0040158B   mov         eax,dword ptr [ebp-20h]
    0040158E   mov         dword ptr [eax],2
    00401594   mov         ecx,dword ptr [ebp-20h]
    

    即申请完空间后,编译器自动生成代码将初始值放入刚申请的空间中

    最后以一个例子结束,注释已经写的很清楚了,就不作解释

    #include<iostream>
    #include<new>
    using namespace std;
    //重载new操作符,注意区分new.h中定义的两个operator new
    void * operator new(size_t size,int data);
    int main()
    {
    	//调用重载的operator new 
    	int *p=(int *)operator new(sizeof(int),10);
    	*p=2;
    	cout<<*p<<endl;
    	//调用重载的operator new,并且传入第二个参数为10,第一参数不需要传入
    	int *tmp=new(10) int(5);
    	cout<<*tmp<<endl;
    	//声明一个空结构体,表示不抛出异常
    	nothrow_t exp;
    	//调用new或者new.h中定义的void *__cdecl operator new(size_t, const std::nothrow_t&)	_THROW0();
    	int *tmpS=new (exp)int(20);
    	cout<<*tmpS<<endl;
    	return 0;
    }
    //重载的new函数
    void * operator new(size_t size,int data)
    {
    	cout<<data<<endl;
    	return operator new(sizeof(int));
    }
  • 相关阅读:
    Gitcafe绑定自定义域名
    如何优雅地使用Sublime Text
    使用Hexo搭建专属Blog
    How to Use Android ADB Command Line Tool
    雷军北大15分钟演讲:我至少有胆量去想(转)
    浅谈android中的目录结构
    react里 MD5加密
    git忽略相应文件夹,不上传
    antd-mobile的按需加载
    当react 项目使用px2rem
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3109014.html
Copyright © 2011-2022 走看看