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
C++ new/new operator、operator new、placement new初识相关推荐
- C++ 中 new 操作符内幕:new operator、operator new、placement new
一.new 操作符(new operator) 人们有时好像喜欢有意使C++语言的术语难以理解.比方说new操作符(new operator)和operator new的差别. 当你写这种代码: st ...
- C++中的new、operator new与placement new
C++中的new/delete与operator new/operator delete new operator/delete operator就是new和delete操作符,而operato ...
- 错误解析 error:unable to find numeric literal operator ‘operator““a/b/c/...‘
当出现 error:unable to find numeric literal operator 'operator""c'或者 'b8'/ 'xx' was not decla ...
- c++中的new、operator new、placement new
一.定义 1.new new是c++中的关键字,,其行为总是一致的.它先调用operator new分配内存,然后调用构造函数初始化那段内存. new 操作符的执行过程: 1. 调用operator ...
- operator new与placement new
通常讲的new指的是new operator,使用new operator的时候,实际上执行了三个步骤: 1)调用operator new分配内存 :2)调用构造函数生成类对象:3)返回相应指针. 分 ...
- c++ error: unable to find numeric literal operator ‘operator““n‘|
代码: #include <stdio.h>int main(){int n;scanf("%d",&n);int cnt=0;while(n!=1){if(n ...
- python operator 多属性排序_又碰到一个非常实用的模块,以后的各种运算就用它了,python内置的常用包。
在工作中,经常对数据进行各种运算,如要从一个序列中返回一个新的序列,亦或是要对两个数进行比较或者进行加和操作等.如果只是一个简单的运算,怎么都好办.但如果我们面对的是比较复杂的需求时,可能我们更多的是 ...
- .net转换关键字:operator、explicit与implicit
operator.explicit与implicit 很少用到,但也不能不知道,发现这篇写很好,转一篇 operator operator 关键字用于在类或结构声明中声明运算符.运算符声明可以采用下列 ...
- 云原生时代 RocketMQ 运维管控的利器 - RocketMQ Operator
作者 | 刘睿.杜恒 导读:RocketMQ Operator 现已加入 OperatorHub,正式进入 Operator 社区.本文将从实践出发,结合案例来说明,如何通过 RocketMQ Ope ...
最新文章
- windows下qt5 kinect 2.0开发与环境配置
- 建立海盗的天堂:盗贼之海的AI设定(三):巨齿鲨、海怪和骷髅船的AI运行
- OpenCV3.0或OpenCV3.1的SVM操作
- ConcurrentHashMap的源码分析-CounterCells初始化图解
- r语言做绘制精美pcoa图_R语言统计与绘图:绘制QQ图
- JVM 参数使用总结
- 寓言故事中隐藏的10个成功秘诀
- 5919. 所有子字符串中的元音
- 23种设计模式介绍(一)---- 创建型模式
- 开发技术理论学习与实践的关系
- Android项目目录结构中各个文件夹的作用
- 第H题 输入N求N的阶乘的10进制表示的长度
- 解决 Orange Pi 烧录完系统后剩余可用空间过少的问题
- c语言能编写嵌入式程序吗,嵌入式c语言编程之嵌入式c语言编程思想
- WEB API 接口签名sign验证入门与实战
- Windows10微软商店打不开怎么办?
- php解析手机号 归属地,PHP通过API获取手机号码归属地,api手机号码_PHP教程
- mysql管理员权限哪个表_Mysql 用户权限管理(权限列表)
- Python内建函数与对象方法
- 计算机科学与技术肄业后怎么继续完成学业,学籍学分问题解答
热门文章
- [源码学习]调试Razor从哪里开始
- WinXP启动时自动打开上次关机时未关闭的文件夹
- 消息队列mysql redis那个好_Redis与RabbitMQ作为消息队列的比较
- 利用C语言创建和使用DLL文件
- 搜索时,怎样排除不需要的关键字
- 基类数组存放派生类_永远不要将派生类数组赋值给基类类型指针
- java实现123n_java三线程交替打印123……n
- 计算机的iscsi配置,PC端的iSCSI参数设置方法
- sinaapp mysql连接_手把手教你在新浪云上免费部署自己的网站--连接数据库
- 将url参数字符串转成数组