C++ new/new operator、operator new、placement new初识

简要释义

1.operator new是内存分配函数(同malloc),C++在全局作用域(global scope)内提供了3份默认的operator new实现,并且用户可以重载operator new。

1 void* operator new(std::size_t) throw(std::bad_alloc);//normal new
2 void* operator new(std::size_t,const std::nothrow_t&) throw();//nothrow new
3 void* operator new(std::size_t,void*) throw();//placement new

下面这两行代码是等价的,都是分配一块大小为sizeof(widget)的内存并返回指针,没有执行构造函数

1 widget *a=(widget*) ::operator new(sizeof(widget));
2 widget *b=(widget*)malloc(sizeof(widget));

2.new/new operator即C++内置的new操作符。

//这里new一个widget对象分成两步
//1.运行期系统调用operator new开辟sizeof(widget)大小的内存
//2.在该内存地址上构造一个widget对象
widget *c=new widget();

我们平常的new操作由运行期系统调用operator new,然后调用构造函数初始化。这个过程是不可重定义的。即程序员不能重载C++内建的new操作符。我们能重载的仅是其中的 operator new/operator new[],即分配内存的部分。

3.placement new是operator new在全局作用域上的一个重载版本,即如上我们看到的

1 void* operator new(std::size_t,void*) throw();//placement new

 placement new并不分配内存,而是返回已分配的内存的指针,这个指针正是函数参数列表中的void *,即“返回一个你刚传入的已分配的内存的指针”。

std::中该函数的实现:

1 inline _LIBCPP_INLINE_VISIBILITY void* operator new  (std::size_t, void* __p) _NOEXCEPT {return __p;}

 那么为什么需要这个placement new呢?

答案是:当你需要在一段已分配的内存中构造对象时,调用寻常的new widget()会开辟另外一个内存空间,而非在已知地址上构造widget()对象。

//这里先申请了一段内存空间,由指针widget*a持有,并未调用构造函数
//然后用placement new在a地址上构造了widget对象
//这里::表示调用在global scope中的匹配函数
widget *a=(widget*) ::operator new(sizeof(widget));
::new(a) widget();

 

进一步的讨论

1.placement new实质上是有额外实参之operator new,一般情况下我们指的placement new是那个额外实参为void*的重载版本(已被纳入C++标准程序库),这些叫法对我们的讨论没有影响,只要知道placement new同时也是一种operator new即可。但是不要忘了我们可以重载其它版本的placement new,例如额外实参为std::ostream&,提供log功能。

 1 #include <iostream>
 2 class widget
 3 {
 4 public:
 5     static void * operator new(std::size_t _size,std::ostream& o)
 6     {
 7         o<<"void * operator new(std::size_t _size,ostream& o)"<<std::endl;
 8         return ::operator new(_size);
 9     }
10     widget()
11     {
12         std::cout<<"widget()"<<std::endl;
13     };
14     ~widget()
15     {
16         std::cout<<"~widget()"<<std::endl;
17     };
18 
19 };
20 int main()
21 {
22     //下面两种构造方法是等价的
23     //构造一个widget对象,并且使用有log功能的operator new
24     widget* a=(widget*) widget::operator new(sizeof(widget), std::cout);
25     ::new(a) widget();
26     
27     //同样构造一个widget对象,并且使用有log功能的operator new
28     widget* b=new(std::cout) widget();
29     return 0;
30 }

 

这份示例代码中,我在类中重载了placement new,附带的额外参数是ostream&。

 

2.注意作用域遮掩问题。如果你在类内重载了一个operator new,当你对这个类及其子类使用new操作符的时候,会掩盖全局作用域中的operator new,编译器发现里层作用域(类内)有operator new声明,就不会查找全局作用域是否有其它operator new声明,而是直接进入参数匹配阶段,如果你重载的operator new参数和调用的不匹配,便会抛出一个编译错误。

解决方法就是:如果类内重载了operator new,并且你仍有可能使用到全局作用域中的operator new,请同时也重载和全局作用域同型的operator new,确保调用成功。

为你的类建立一个base class,内含全局作用域同型的operator new,使其调用全局作用域内的operator new即可。

 1 #include <iostream>
 2 class globalScopeNew
 3 {
 4 public:
 5     static void* operator new(std::size_t size) throw(std::bad_alloc)
 6     {
 7         return ::operator new(size);
 8     }
 9     static void* operator new(std::size_t size,const std::nothrow_t& t) throw()
10     {
11         return ::operator new(size, t);
12     }
13     static void* operator new(std::size_t size,void* p) throw()
14     {
15         return ::operator new(size, p);
16     }
17     
18 };
19 class widget:public globalScopeNew
20 {
21 public:
22     using globalScopeNew::operator new;
23     static void * operator new(std::size_t _size,std::ostream& o)
24     {
25         o<<"void * operator new(std::size_t _size,ostream& o)"<<std::endl;
26         return ::operator new(_size);
27     }
28     widget()
29     {
30         std::cout<<"widget()"<<std::endl;
31     };
32     ~widget()
33     {
34         std::cout<<"~widget()"<<std::endl;
35     };
36    
37 };
38 int main()
39 {
40     widget* w2=new(std::cout) widget();
41     //这句调用原来不能通过编译
42     widget* w1=new widget();
43     widget* w3=(widget*)operator new(sizeof(widget));
44     //这句调用原来不能通过编译
45     new(w3) widget();
46     return 0;
47 }

 

注意,这边需要在子类中using globalScopeNew::operator new;即在子类中使基类的operator new可见。

这样,各种形式的new操作符调用都能通过编译了。

转载于:https://www.cnblogs.com/kyokuhuang/p/4199724.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/376360.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

160 - 45 Dope2112.2

环境&#xff1a; Windows xp sp3 工具 1.ollydbg 2.exeinfope 0x00 查壳 还是无壳的Delphi程序 0x01 分析 这次继续OD载入搜字符串&#xff0c;但是没找到错误信息的字符串。 又因为是Delphi程序&#xff0c;所以可以试一下这样&#xff1a; OD载入后还是搜字符串&…

编辑技巧 word

怎样给word中的文档加上水印 转载于:https://www.cnblogs.com/dqxu/p/4208372.html

NAT地址转换原理全攻略

NAT转换方式及原理 在NAT的应用中&#xff0c;可以仅需要转换内部地址&#xff08;就是“内部本地址”转换成“内部全局地址”&#xff09;&#xff0c;这是最典型的应用&#xff0c;如内部网络用户通过NAT转换共享上网&#xff1b;也可以是仅需要转换外部地址&#xff08;就是…

通过setTimeout来取消因大量计算造成的网页卡顿

js是单线程的&#xff0c;所以有些大量计算的操作会占用线程资源&#xff0c;导致页面卡住。 今天遇到这样一个场景&#xff0c;选择一个下拉框之后&#xff0c;对数据进行筛选&#xff0c;这个过程中有大量计算&#xff0c;点了selecte的option之后&#xff0c;option不隐藏&a…

160 - 47 DueList.2

环境&#xff1a; Windows xp sp3 工具&#xff1a; Ollydbg exeinfope 0x00 查壳 无壳的程序 0x01 分析 运行后说需要keyfile&#xff0c;那就创建一个。 OD载入找找看需要的keyfile叫什么名字 00401000 > $ 6A 00 push 0x0 …

如何解决Visual Studio2012 与此版本的Windows不兼容

解决方案&#xff1a; http://www.microsoft.com/zh-CN/download/details.aspx?id36020 下载更新转载于:https://www.cnblogs.com/awodefeng/p/3373343.html

160 - 48 DueList.3

环境&#xff1a; Windows xp sp3 工具&#xff1a; Ollydbg exeinfope 0x00 查壳 无壳的程序 0x01 分析 应该就是选上某个或多个框后点Check就能成功的&#xff0c;那应该就是不同框对应不同的值咯。旁边还有个提示&#xff1a;建议使用资源编辑器。 直接OD载入&#x…

为什么django+mongo在windows上session能够获取到,同样的程序在linux上就会报session的变量错误,keyerror?...

settings&#xff1a;SESSION_ENGINE django.contrib.sessions.backends.cache 其它地方&#xff1a;正常存取值。request.session["mm"]“MM” 转载于:https://www.cnblogs.com/angelfeeling/p/4211261.html

图片上传 关于压缩的问题

图片上传 关于压缩的问题 如果不压缩&#xff0c;图片的数据量非常大&#xff0c;很影响上传速度 http://blog.csdn.net/jinglijun/article/details/8751269 http://blog.csdn.net/jinglijun/article/details/8751220转载于:https://www.cnblogs.com/kevingod/p/3375507.html

160 - 49 DueList.4

环境&#xff1a; Windows xp sp3 工具&#xff1a; ollydbg exeinfope 0x00 查壳 无壳的程序 0x01 分析 运行后随便输入点东西&#xff0c; OD载入&#xff1a; 00401127 > /6A 00 push 0x0 ; /lParam 0 00401129 …

java中的codereview

&#xfeff;&#xfeff;关于codereview&#xff0c;在平时的开发中&#xff0c;经常忽略的环节&#xff0c;参照目前介绍写好代码的几本书和之前掉进的坑&#xff0c;做了一个总结&#xff0c;分享出来。 为什么要做 通过review规避一些代码层面的问题提升可读性&#xff0c;…

linux下开机启动脚本的方法

1.准备好要随机启动的程序&#xff0c;例如 /root/test.sh 。确保其可执行。 2.在目录 /etc/init.d/ 下编写控制脚本 test 。 #!/bin/sh ### BEGIN INIT INFO # Provides: test # Required-Start: $remote_fs # Required-Stop: $remote_fs # Default-Start: …

理解i-node

原文链接:http://www.ruanyifeng.com/blog/2011/12/inode.html 感觉讲得挺好,便做个记录.转载于:https://www.cnblogs.com/malware/p/3377616.html

MD5算法详解

0x00 前言 MD5是一种哈希算法&#xff0c;用来保证信息的完整性。 就一段信息对应一个哈希值&#xff0c;且不能通过哈希值推出这段信息&#xff0c;而且还需要保证不存在任意两段不相同的信息对应同一个哈希值。不过MD5算法算出来的值也就16个字节&#xff08;16*8128&#x…

我的2015年读书计划,每两周读完一本书!

近日看到一篇文章&#xff0c;说Facebook CEO 马克扎克伯格给自己的2015年定下了一个新的挑战&#xff0c;每两周就要读完一本书&#xff08;传送门&#xff1a;戳这里&#xff09;。想了一下&#xff0c;我自己也很久没看书了&#xff0c;所以今年要改变一下&#xff0c;给自己…

书到用时方恨少

以前觉得的自己的英语还行&#xff0c;四级&#xff0c;六级的什么早就在读书的时候过了&#xff0c; 工作以后&#xff0c;陆陆续续也一直用着英语。 最近发现和老外私下聊天的时候&#xff0c;词汇量严重不足。不明白老外在说什么&#xff0c;一起跟着傻笑。 活到老&#xff…

kettle7.1 右上角不显示connect

kettle7.1右上角不显示connect&#xff0c;就无法使用资源库了。 总结一下解决方法&#xff1a; 1.可能是jdk版本不对&#xff0c;最好使用1.8。原本是10.1&#xff0c;不显示connect&#xff0c;后来装了个1.8后就能显示了。记得是要改环境&#xff0c;javac -version 能显示…

基于XMPP协议的aSmack源码分析

在研究如何实现Pushing功能期间&#xff0c;收集了很多关于Pushing的资料&#xff0c;其中有一个androidnp开源项目用的人比较多&#xff0c;但是由于长时间没有什么人去维护&#xff0c;听说bug的几率挺多的&#xff0c;为了以后自己的产品稳定些&#xff0c;所以就打算自己研…

[Reverse] - 百度杯”CTF比赛 2017 二月场-CrackMe-1

环境&#xff1a;Windows XP 工具&#xff1a; IDA OD EXEINFOPE 0x00 查壳 0x01 分析 拖入OD&#xff0c;字符串查找看一看。 跟进去看就可以知道关键call了 0040196A . 48 dec eax 0040196B . 0F85 C4000000 jnz CrackMe1.00401A35 00401971 . …

【DeepLearning】Exercise:Learning color features with Sparse Autoencoders

Exercise:Learning color features with Sparse Autoencoders 习题链接&#xff1a;Exercise:Learning color features with Sparse Autoencoders sparseAutoencoderLinearCost.m function [cost,grad,features] sparseAutoencoderLinearCost(theta, visibleSize, hiddenSize,…