c++中new与delete的重载

  对于有一定编程基础的人来说,new与delete一定会非常的熟悉,知道在使用的过程中:new 先分配memory(内存)再调用ctor(构造函数);而delete是先调用dtor(析构函数)再释放memory。


int * p=new int[10];
int * pa=new int(10);

  new用来动态创建数据或者单个对象;对于上面的代码,第一行是用new 动态创建一个长度为10的数据,指针p指向数组的首地址;而代码第二行是用new创建一个单个的对象,单个的对象为整型数10,指针pa指向这个对象的地址。


  对于使用方法,在本次博文中不做详细的讲解,本文主要讲解new和delete的重载。请看下面的例子(重载一个全局的new和delete):

//以下代码将new和delete进行了全局重载
void * myAlloc(size_t size)
{
	return malloc(size);
}
void myfree(void * ptr)
{
	return free(ptr);
}
//它们不可以被申明在一个namespace内
inline 
void * operator new(size_t size)
{
	cout << "global new    "; return myAlloc(size);
}
inline 
void * operator new[](size_t size)
{
	cout << "global new[]   "; return myAlloc(size);
}
inline
void operator delete(void * ptr)
{
	cout << "global delete   "; return myfree(ptr);
}
inline void operator delete[](void * ptr)
{
	cout << "global delete[]   "; return myfree(ptr);
}

  如果程序中写成上面的代码形式,则此时new和delete被重载成了全局的形式。那么如果对一个class里面重载 member operator new/delete 应该如何操作呢,请看下面的参考代码(如果需要对一个class中的new和delete进行重载可以参考下面的代码(下方代码的“…”部分需要用户根据自己的需求进行自定义)

//以下代码适合在一个class中对new 和delete的重载过程进行理解(仅供参考)
class Foo{
public:
	int _id;
	long _data;
	string _str;
public:
	Foo() :_id(0){ cout << "default ctor this= " << this << "id= " << _id << endl; }
	Foo(int i) :_id(i){ cout << "ctor this = " << this << "_id" << _id << endl; }
	//virtual
	~Foo(){ cout << "dtor this= " << this << "id=" << _id << endl; }
	static void * operator new(size_t size);
	static void operator delete(void * pdead, size_t size);
	static void * operator new[](size_t size);
	static void operator delete[](void *pdead, size_t size);
};
void * Foo::operator new(size_t size){
	Foo * p = (Foo *)malloc(size);
	cout << ......;//此处用户自行定义
	return p;
}
void Foo::operator delete(void * pdead, size_t size){
	cout << ......;
	free(pdead);
}
void * Foo::operator new[](size_t size){
	Foo * p = (Foo *)malloc(size);
	cout << ......;
	return p;
}
void Foo::operator delete[](void * pdead, size_t size){
	cout << .....;
	free(pdead);
}
使用时用法:
Foo * pf = new Foo;
delete pf;
Foo * pd = new Foo[size];
delete []  pd;

  通过上方的例子相信大家对于在C++中如何实现new和delete的全局重载,以及在一个class中对new和delete进行重载有了一定的了解,但是我们要记住的是new与delete是配套出现的,尤其是对于new一个数据时,最后必须要有配套的delete对其进行内存的释放。


  但是对new和delete使用中如果遇到下方的这种情况则一定需要注意(如下):

Foo * pf=::new Foo;
delete pf;

  如果遇到上面的这种情况,即:用户已经在class中对new和delete进行了重载,但是使用中如果遇到上面这种情况(在new的前面加上“::”符号)时,则表示此时绕过了自己重载的运算符new,而是调用了全局的new运算符。


  对于上面的代码里面写的class Foo中的数据成分,可以知道,含有一个int型数据,一个long型数据,一个string型数据,而从内存的角度分析:一个int占4个字节,一个long型数据也是占4个字节,而一个string型的数据它实际是一个指针,而一个指针占4个字节,所以此时我们如果要求Foo占得字节,可以得到:

sizeof(Foo)的值为12

 & 如果给Foo 类添加一个虚函数时,更具我之前说的虚指针与虚表的分析可以知道当加上了虚函数后,那么它的对象就会多一个指针,而一个指针占4个字节,则加上虚函数后sizeof(Foo)=16.


  那么如果对于Foo这个类型,我需要new一个数据类型为Foo的数组,它的内存又是如何变化的呢,如下:

Foo * Array=new Foo[5];
delete [] Array;

  那么此时sizeof(Foo)=64;大家可能会觉得奇怪,一个单一的Foo对象sizeof的值是12,那么上面的这个数组对应的sizeof不是应该是12*5=60么,多出的4个字节是哪里来的。其实当new一个数组时,Foo类型这个数组实际占的字节大小等于  Array的整包大小12乘以5等于60,然后在加上一个计数器来记录有几个Foo类型的数据,而这个计数器的大小占4个字节,所以最后他的大小60+4=64个字节。 那么如果与virtual结合呢,他的大小将变成(12+4)*5+4=84个字节。


  遇到重载new()和delete()时:


  在这之前我们说的new和delete的重载,是operator new;operator delete和operator new[];oprator delete[],除了这两种重载方法外,我们还可以重载class member operator new(),写出多个版本,前提是每一个版本的声明都必须有独特的参数列,其中**第一参数必须是size_t 型,**其余参数以new所指定的placement arguments 为初值,出现new(…),小括号内便是所谓的placement argument 。如:

Foo * pf=new(300,'c')Foo;

  我们也可以重载class member operator delete(),写出多个版本,但他们绝不会被delete调用,只有当new所调用挂的ctor(构造函数)跑出exception时才会调用这些重载版的operator delete(),它只可以这样来调用,主要用来归还未能完全创建成功的object所占用的memory。


  下方为new()的参考:

void * oprerator new(size_t size ,void * start){
    return start;
}

void * operator new(size_t size ,long extra){
    return malloc(size+extra);
}

void * operator new(size_t size ,long extra,char inti){
    return malloc(size+extra);
}

  对于文中错误的地方或者表述不正确的地方,还请大家能够在评论区给与指正,谢谢!
  C++更多文章请点击这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值