C++一些注意点之operator new 和new operator

         在C++中,operator new和new operator还是很有区别。new operator是c++内建的,无法改变其行为;而operator new 是可以根据自己的内存分配策略去重载的。

1. operator new

       operator new和operator delete有两个重载版本,每个版本支持相关的new表达式和delete表达式:

                 void *operator new(size_t);

                 void *operator new[](size_t);

                 void *operator delete(void*);

                 void *operatordelete[](void*);

对于operator new你可以对其进行重载,但是必须注意:

       (1) 只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则如果有new_handler,则调用new_handler;否则如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常;否则返回0。(这个调用顺序要记住,可以通过set_new_handler()函数设置new_handler)

      (2) 重载时,返回类型必须声明为void*

      (3) 重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t

      (4) 重载时,可以带其它参数。

注:当然重载了operator new,你就要重载对应的operator delete。

    operator new实际上总是以标准的C malloc()完成,虽然并没有规定非得这么做不可。同样,operator delete也总是以标准得C free()来实现,不考虑异常处理的话他们类似下面的样子: 

extern void* operator new( size_t size ) 
{ 
  if( size == 0 ) 
  size = 1; // 这里保证像 new T[0] 这样得语句也是可行的 
   
  void *last_alloc; 
  while( !(last_alloc = malloc( size )) ) 
  { 
     if( _new_handler ) 
         ( *_new_handler )(); //调用handler函数
     else 
         return 0; 
  } 
  return last_alloc; 
  
} 
extern void operator delete( void *ptr ) 
{ 
  if(ptr) // 从这里可以看出,删除一个空指针是安全的 
  free( (char*)ptr ); 
}

2. new operator 

     当你写string *ps = new string("Hands up!")时,你所使用的new是所谓的new operator,它其实干了两件事:一、分配足够的内存(实际大小是大于所创建的对象大小)二、调用对象构造函数,new operator永远干这两件事。上面的那段代码大约反映以下的行为:
               void *mem = operator new(sizeof(string));
               call string::string("Hands up!") on *mem;//只能由编译器完成,用户是不允许这样操作的,也就是说如果你想建立一个堆对象就必须用new操作符,不能直接像上面一样调用构造函数来初始化堆对象。 
               string *ps = static_cast<string*>(mem);
      也就是说operator new仅仅分配内存(就像malloc一样),我们能够做的仅仅是重载operator new,为自己的类创建一个定制的内存管理方案,这也让我有点明白为什么在重载operator new的时候并没有写调用构造函数的代码,但它确实被调用了,原来都是new operator搞的鬼。

     编译器看到类类型的new或者delete表达式的时候,首先查看该类是否是有operator new或者operator delete成员,如果类定义了自己的new和delete函数,则使用这些函数为对象分配和释放内存,否则调用标准库版本。如果你想定制自己独有的内存分配过程,你应该重载全局的operator new函数,然后使用new操作符,new操作符会调用你定制的operator new。当然你可以显示的调用:: operator new和:: operator delete强制使用全局的库函数。下面:

                Type *p = :: new Type;//该new operator会调用全局的operator new

               ::delete p;//该delete operator会调用全局的operator  delete 

       建立数组时new操作符(new[])的行为与单个对象建立(new)有少许不同:第一是内存不再调用用operator new函数进行分配,代替以operator new[]函数(常称作array new)。它与operator new一样能被重载,允许定制数组的内存分配,就象定制单个对象内存分配一样。 

3. 定位new表达式

      类似于constructor成员,有第三种new表达式,称为定位new(placement new)。定位new表达式在已分配的与原始内存中初始化一个对象,他与new的其他版本不同,它不分配内存。相反,它接受指向已分配好但未构造的内存指针,并在该内存中初始化一个对象。实际上,定位new表达式使我们在特定的、预分配的内存地址构造一个对象。它可以定义类的任何构造函数。

                new(place_address) type

                new(place_address) type(initializer_list)

place_address必须是一个指针,而initializer_list提供了初始化列表(可能是空的),以便在构造新分配的对象中使用。

4. 使用注意点

     如果只考虑分配和释放,内存管理基本要求是“不重不漏”:既不重复 delete,也不漏掉 delete。也就说我们常说的 new/delete 要配对,“配对”不仅是个数相等,还隐含了 new 和 delete 的调用本身要匹配,不要“东家借的东西西家还”。例如:

 (1)用系统默认的 malloc() 分配的内存要交给系统默认的 free() 去释放;

 (2)用系统默认的 new 表达式创建的对象要交给系统默认的 delete 表达式去析构并释放;

 (3) 用系统默认的 new[] 表达式创建的对象要交给系统默认的 delete[] 表达式去析构并释放;

 (4) 用系统默认的 ::operator new() 分配的的内存要交给系统默认的 ::operator delete() 去释放;

 (5) 用 placement new 创建的对象要用 placement delete (为了表述方便,姑且这么说吧)去析构(其实就是直接调用析构函数);

 (6)从某个内存池 A 分配的内存要还给这个内存池。

 (7) 如果定制 new/delete,那么要按规矩来。见 Effective C++ 相关条款。



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值