当前位置: 首页 > 工具软件 > newBlog > 使用案例 >

C++ operator new和new operator区别

赵俊晤
2023-12-01

在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 ); 
}
  1. 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一样能被重载,允许定制数组的内存分配,就象定制单个对象内存分配一样。 
    
  2. 定位new表达式

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

             new(place_address) type
    
             new(place_address) type(initializer_list)
    

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

  1. 使用注意点
    如果只考虑分配和释放,内存管理基本要求是“不重不漏”:既不重复 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,那么要按规矩来。见EffectiveC++相关条款。

转自:https://blog.csdn.net/lsjseu/article/details/9206883

 类似资料: