你真的了解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));
}
原文地址:https://www.cnblogs.com/javawebsoa/p/3109014.html