博客:https://goodfanqie.github.io(文章优先展示地方,推荐在此阅读。)

new做了哪些:

在c++中,对new的调用时,new完成的工作通常是有以下几步:

  1. 调用operator new函数分配出内存
  2. 待用对象的构造方法构造出对象
  3. 返回该对象的指针

operator new
(1)只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则
->如果有new_handler,则调用new_handler,否则
->如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则
->返回0
(2)可以被重载
(3)重载时,返回类型必须声明为void*
(4)重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t
(5)重载时,可以带其它参数

opeartor new重载测试

class X
{public:X() { cout<<"constructor of X"<<endl;}~X() { cout<<"destructor of X"<<endl;}void* operator new(size_t size,string str){cout<<"operator new size "<<size<<" with string "<<str<<endl;return ::operator new(size);}void operator delete(void* pointee){cout<<"operator delete"<<endl;::operator delete(pointee);       //调用全局的 operator delete函数}
private:int num;
};int main()
{X *px = new("A new") X;delete px;return 0;
}// 输出结果
// operator new size 4 with string A new
// constructor of X
// destructor of X
// operator delete

那么为什么要重载operator new函数呢?首先第一点当然是因为new作为一种操作符是不能被重载的,而作为new中重要的一环:分配内存,重载operatir new就变的一种必要的操作了。全局opeartor new在分配内存时,实际上也是对malloc的一层包装,在进行大量次数的内存分配时容易出现内存碎片的问题,通过重载operator new函数可以自定的将内存分配在独立出来的一块内存区域,可以更高效率的实现内存分配的管理,同时也可以有效减少内存碎片化以及不易与管理的问题。

重载operator new函数还有很多的用途,比如,他可以帮助我们查找内存泄漏,在c++中,内存泄漏是痛中之痛,重载该函数并与宏定义相配合可以很好的检测出内存泄漏的地方在哪里。相关文章链接:https://blog.51cto.com/u_15060533/4689267

placement new

placement new是operator new的一个重载版本,他的作用是可以将一个对象分配到指定的内存空间。实现代码如下:

void* operator new(std::size_t, void* __p) throw()
{return __p;
}

placement new 只是operator new的一个重载版本,只是起了一个别名而已.
代码示例:

class A{int num;
public:A(){cout<<"A's constructor"<<endl;}~A(){cout<<"~A"<<endl;}void show(){cout<<"num:"<<num<<endl;}
};int main()
{char* mem;cout << (void*)mem << endl;A* a = new(mem) A;cout << (void*)a << endl;return 0;
}// 0x104e570ac
// A's constructor
// 0x104e570ac

阅读以上程序,注意以下几点。
(1)用定位放置new操作,既可以在栈(stack)上生成对象,也可以在堆(heap)上生成对象。如本例就是在栈上生成一个对象。

(2)使用语句A* p=new (mem) A;定位生成对象时,指针p和数组名mem指向同一片存储区。所以,与其说定位放置new操作是申请空间,还不如说是利用已经请好的空间,真正的申请空间的工作是在此之前完成的。

(3)使用语句A *p=new (mem) A;定位生成对象是,会自动调用类A的构造函数,但是由于对象的空间不会自动释放(对象实际上是借用别人的空间),所以必须显示的调用类的析构函数,如本例中的p->~A()。

(4)万不得已才使用placement new,只有当你真的在意对象在内存中的特定位置时才使用它。例如,你的硬件有一个内存映像的I/O记时器设备,并且你想放置一个Clock对象在哪那个位置。

在一些高效率的程序中,往往会开辟出一块独立的内存空间配合placement new来实现高效率的内存释放与配置,如在SGI STL的内存配置函数allocate 与 deallcate函数,以及大名鼎鼎的memory pool技术都很大程度上依靠了placement new定位创建对象。在快速的内存分配与释放的过程中这是一个非常实用的方法。

Placement new使用步骤

在很多情况下,placement new的使用方法和其他普通的new有所不同。这里提供了它的使用步骤。

第一步 缓存提前分配

有三种方式:

  1. 为了保证通过placement new使用的缓存区的memory alignment(内存队列)正确准备,使用普通的new来分配它:在堆上进行分配
class Task ;
char * buff = new [sizeof(Task)]; //分配内存
(请注意auto或者static内存并非都正确地为每一个对象类型排列,所以,你将不能以placement new使用它们。)
  1. 在栈上进行分配
class Task ;
char buf[N*sizeof(Task)]; //分配内存
  1. 还有一种方式,就是直接通过地址来使用。(必须是有意义的地址)
void* buf = reinterpret_cast<void*> (0xF00F);

第二步:对象的分配

在刚才已分配的缓存区调用placement new来构造一个对象。

Task *ptask = new (buf) Task

第三步:使用

按照普通方式使用分配的对象:

ptask->memberfunction();
ptask-> member;
//...

第四步:对象的析构

一旦你使用完这个对象,你必须调用它的析构函数来毁灭它。按照下面的方式调用析构函数:

ptask->~Task(); //调用外在的析构函数,显式调用!

第五步:释放

你可以反复利用缓存并给它分配一个新的对象(重复步骤2,3,4)如果你不打算再次使用这个缓存,你可以象这样释放它:

delete [] buf;

总结:

(1)若想在堆上建立一个对象,应该用new操作符。它既分配内存又调用其构造函数进行初始化。
(2)若仅仅想分配内存,应该调用operator new(),他不会调用构造函数。若想定制自己在堆对象被建立时的内存分配过程,应该重写自己的operator new()。
(3)若想在一块已经获得的内存空间上建立一个对象,应该用placement new。在实际开发过程中,这种写法一般在高性能高稳定场景下使用。本文主要是为了更好的理解STL源码中alloator的内存管理行为所写。

理解可能并不规范,表达也会有所纰漏。
参考文章:

  1. https://cloud.tencent.com/developer/article/1177460
  2. https://blog.51cto.com/u_15060533/4689267
  3. https://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html

C++中的opeartor new和placement new详解相关推荐

  1. oracle中的exists 和 not exists 用法详解

    from:http://blog.sina.com.cn/s/blog_601d1ce30100cyrb.html oracle中的exists 和 not exists 用法详解 (2009-05- ...

  2. R语言中如何计算C-Statistics?几种计算方法详解

    R语言中如何计算C-Statistics?几种计算方法详解 目录 R语言中如何计算C-Statistics? #包导入 #数据加载编码

  3. python中的class怎么用_对python 中class与变量的使用方法详解

    python中的变量定义是很灵活的,很容易搞混淆,特别是对于class的变量的定义,如何定义使用类里的变量是我们维护代码和保证代码稳定性的关键. #!/usr/bin/python #encoding ...

  4. java中sleep()、wait()相同与不同详解

    java中sleep().wait()相同与不同详解 相同 java中Thread#sleep和Object#wait方法都是暂停当前线程,当前线程让出CPU占用.并不存在调用sleep后还占用CPU ...

  5. python爬取图片-Python爬取网页中的图片(搜狗图片)详解

    前言 最近几天,研究了一下一直很好奇的爬虫算法.这里写一下最近几天的点点心得.下面进入正文: 你可能需要的工作环境: Python 3.6官网下载 本地下载 我们这里以sogou作为爬取的对象. 首先 ...

  6. object类中的equals与自定义equals方法详解

    object类中的equals与自定义equal方法详解 1.this怎么理解?this == obj表示什么? this就是当前你new出来的对象,这里指谁调用equal方法this指的就是谁,ob ...

  7. php 修改 wordpress,修改WordPress中文章编辑器的样式的方法详解

    这篇文章主要介绍了修改WordPress中文章编辑器的样式的方法详解,同时文中也推荐了两款取代默认文章编辑器的插件,需要的朋友可以参考下 自定义文章编辑器的样式每一个 WordPress 主题的文章样 ...

  8. python中class变量_对python 中class与变量的使用方法详解

    python中的变量定义是很灵活的,很容易搞混淆,特别是对于class的变量的定义,如何定义使用类里的变量是我们维护代码和保证代码稳定性的关键. #!/usr/bin/python #encoding ...

  9. mysql group by having count_mysql中count(), group by, order by使用详解

    最近做IM的时候遇到一个问题,同时用到了这三个关键字.就是查询一个人的离线消息详情,我们服务端返回给客户端显示的这个详情包括了三个内容,第一个要求列出离线这段时间哪些人或者群给你发了消息,第二个这其中 ...

最新文章

  1. Png透明背景的电话图标。
  2. 实战:CNN+BLSTM+CTC的验证码识别从训练到部署 | 技术头条
  3. 推荐一个用Java实现监控手机短信、来电、App的开源项目
  4. 函数中数据存储的问题
  5. SQLLite (二) :sqlite3_open, sqlite3_exec, slite3_close
  6. 张文宏:知道很多网友批评我,但粥还是不能喝
  7. 纷享逍客宣布完成E+轮融资 长山兴资本领投
  8. docker安装redis【网易镜像方式】
  9. 基于simulink的模糊PID控制器设计与实现
  10. php文字添加投影,PS如何制作文字投影效果 巧用4种方法给文字添加长投影效果...
  11. 开源视频云转码 m3u8_8种开源视频游戏
  12. office2007安装失败2902_Office2007安装出错怎么办?安装出错原因及解决方法分享
  13. oracle 中dummy,layout设计中dummy的作用详解(上图。好贴好贴,讲的很仔细)
  14. 2022牛客多校9 BTwo Frogs(概率DP)
  15. Web漏洞-Xss跨站
  16. 一个老鼠走迷宫问题的python解法
  17. 解决:禁止访问 (403) CSRF验证失败
  18. logstash7.8 apache日志解析 grok
  19. PHP基础-表单数据
  20. 计算机网络图标不见了怎么为,网络连接图标不见了,小编教你网络连接图标不见了怎么办...

热门文章

  1. P5.js开发之——通过createImg向页面中添加图像
  2. 深度解读达芬奇架构:华为AI芯片的“秘密武器”
  3. python opencv 拍照_Python + opencv对拍照得到的图片进行背景去除的实现方法
  4. 追梦五年--跑在奔三的路上
  5. consul watch使用详解
  6. Centos7国内环境下安装kubeadm、kubelet、kubectl并建立k8s集群、安装gitlab,测试spring boot 项目的CICD
  7. 玩转AI(Adobe illustrator)——小西瓜(4)
  8. MySQL插入数据的三种方法
  9. 最实用的深度学习教程 Practical Deep Learning For Coders (Kaggle 冠军 Jeremy Howard 亲授)...
  10. centos卸载不必要的程序_Centos 利用yum安装卸载软件常用命令[转载]