C++之operator new 和new operator区别

举报
琼恩.雪诺 发表于 2017/09/28 16:08:18 2017/09/28
【摘要】 在C++中,operator new和new operator还是很有区别。new operator是c++内建的,无法改变其行为;而operator new 是可以根据自己的内存分配策略去重载的。

在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()来实现,不考虑异常处理的话他们类似下面的样子: 

[code lang="cpp"]
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 );   
}  
[/code]

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一样能被重载,允许定制数组的内存分配,就象定制单个对象内存分配一样。 

  同理:

[code lang="cpp"]
delete ps
[/code]

   上述语句实际上有两步,第一步,对ps所指的对象调用适当的析构函数;第二步,调用名为operator delete的标准库函数释放该对象所用的内存;即delete ps,就相当于delete operator,它的动作分为以下两步:调用析构函数,释放内存空间;即

[code lang="cpp"]
ps->~string();
operator delete(ps);
[/code]

[code lang="java"]
总结: operator new 唯一的任务就是分配内存,new operator的任务是取得 operator new 分配的内存,并将之转换为一个对象,返回一个指向它的指针;同理operator delete的唯一任务是释放内存空间,它不能调用析构函数;
因此,如果你只打算处理原始的、未设初值的内存,应该完全回避new operator 和delete operator,改调用operator new 取得内存并以operator delete归还给系统;
[/code]

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++ 相关条款。

参考:

https://kelvinh.github.io/blog/2014/04/19/research-on-operator-new-and-delete/

作者|分布式资源与管理小组

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:hwclouds.bbs@huawei.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。