[C++空间分配]new运算符、operator new、placement new的区别于联系
先科普一下:
1. new的执行过程:
(1)通过operator new申请内存
(2)使用placement new调用构造函数(内置类型忽略此步)
(3)返回内存指针
2. new和malloc的比较:
(1)new失败时会调用new_handler处理函数,malloc不会,失败时返回NULL
(2)new能通过placement new自动调用对象的构造函数,malloc不会
(3)new出来的东西是带类型的,malloc是void*,需要强制转换
(4)new是C++运算符,malloc是C标准库函数
3. delete的执行过程:
(1)调用析构函数(内置类型忽略此步)
(2)释放内存
4.delete和free的比较
(1)delete能自动调用对象的析构函数,malloc不会
(2)delete是C++运算符,free是C标准库函数
new operator/delete operator就是new和delete操作符,而operator new/operator delete是函数。
new 运算符
(1)调用operator new分配足够的空间,并调用相关对象的构造函数
(2)不可以被重载
operator new
(1)只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则
->如果有new_handler,则调用new_handler,否则
->如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则
->返回0
(2)可以被重载
(3)重载时,返回类型必须声明为void*
(4)重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t
(5)重载时,可以带其它参数
delete 与 delete operator类似
#include <iostream>
#include <string>
using namespace std; 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);//调用全局的operator new申请空间
} void operator delete(void* pointee)
{
cout<<"operator delete"<<endl;
::operator delete(pointee);//调用全局的operator delete释放空间
}
private:
int num;
}; int main()
{
X *px = new("A new class") X;
delete px; return 0;
}
注意::operator new是全局的函数,全局的这样的函数有三个,其中有一个就是placemet new,后面说。一般用户不会(虽然能)在全局重载operator new函数,而是在自定义的类中重载operator new函数。operator new都是申请一个对象的空间内存,所以调用的时候size_t省略,但是对于operator new[]这个函数,要明确的说明数组中对象的个数。
new和delete操作符我们应该都用过,它们是对堆中的内存进行申请和释放,而这两个都是不能被重载的。要实现不同的内存分配行为,需要重载operator new和operator delete,而不是new和delete。
operator new就像operator+一样,是可以重载的。但是不能在全局对原型为void operator new(size_t size)这个原型进行重载,一般只能在类中进行重载。如果类中没有重载operator new,那么调用的就是全局的::operator new来完成堆的分配。同理,operator new[]、operator delete、operator delete[]也是可以重载的。
至于placement new,只是operator new的一个重载的版本,只是我们很少用到它。如果你想在已经分配的内存中创建一个对象,使用new时行不通的。也就是说placement new允许你在一个已经分配好的内存中(栈或者堆中)构造一个新的对象。原型中void*p实际上就是指向一个已经分配好的内存缓冲区的的首地址。
我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。placement new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行,不需要查找内存,内存分配的时间是常数。而且不会出现在程序运行中途出现内存不足的异常。所以,placement new非常适合那些对时间要求比较高,长时间运行不希望被打断的应用程序。 placement new使用方法如下:
1. 缓冲区提前分配,可以使用堆的空间,也可以使用栈的空间。所以分配方式有如下两种:
class MyClass {…};
char *buf = new char[N * sizeof(MyClass)];
char buf[N * sizeof(MyClass)]; 2. 对象的构造
MyClass * pClass = new(buf) MyClass; //使用placement new 3. 对象的销毁
一旦这个对象使用完毕,你必须显式的调用类的析构函数进行销毁对象。但此时内存空间不会被释放,以便其他的对象的构造。
pClass->~MyClass(); 4. 内存的释放
如果缓冲区在堆中,那么调用delete[] buf 进行内存的释放。如果在栈中,那么在其作用域内有效,跳出作用域,内存自动释放。 补充说明:
在C++标准中,对于placement operator new []有如下的说明:
placement operator new[] needs implementation-defined amount of additional storage to save a size of array。
所以我们必须申请比原始对象大小多出sizeof(int)个字节来存放对象的个数,或者说数组的大小。
使用方法第二步中的new才是使用placement new,其实是没有申请内存的,只是调用了构造函数。
返回一个指向已经分配好的内存的一个指针,所以对象销毁的时候不需要调用delete释放空间,但必须调用析构函数销毁对象。
所以对于placement new用于对象数组的时候:
char *buf=new char[N*sizeof(MyClass)+sizeof(int)];
char buf[N*sizeof(MyClass)+sizeof(int)];
MyClass * pClass=new(buf) MyClass[N]; //使用placement new[]
前面说到了全局那里有三个operator new函数,下面看看:
operator new分为三种形式(前2种不调用构造函数,这点区别于new operator):
1: void* operator new (std::size_t size) throw (std::bad_alloc);
2: void* operator new (std::size_t size, const std::nothrow_t & nothrow_constant) throw();
3: void* operator new (std::size_t size, void* ptr) throw();
第一种分配size个字节的存储空间,并进行对象类型进行内存对齐。如果成功,返回一个非空的指针指向首地址。失败抛出bad_alloc异常。
第二种在分配失败时不抛出异常,它返回一个NULL指针。
第三种是placement new版本。它不分配内存,调用合适的构造函数在ptr所指的地方构造一个对象,之后返回实参指针ptr。
三种版本的operator new 定义在全局命名空间,不在std中。第一、第二个版本C++默认在每个编译单元中声明,不需要#include <new>头文件。第一、第二个版本可以被用户更换和重载(一般在类中重载),定义自己的版本,第三种placement new不可重载。
// operator new example
#include <iostream>
#include <new>
using namespace std; struct myclass {myclass() {cout <<"myclass constructed\n";}}; int main ()
{
int * p1 = new int;
// same as:
// int * p1 = (int*) operator new (sizeof(int)); int * p2 = new (nothrow) int;
// same as:
// int * p2 = (int*) operator new (sizeof(int),nothrow); myclass * p3 = (myclass*) operator new (sizeof(myclass));
// (!) not the same as:
// myclass * p3 = new myclass;
// (constructor not called by function call, even for non-POD types) new (p3) myclass; // calls constructor
// same as:
// operator new (sizeof(myclass),p3) return 0;
}
//结果输出:myclass constructed
[C++空间分配]new运算符、operator new、placement new的区别于联系的更多相关文章
- operator new,new operator,placement new的区别
原文地址:http://www.cnblogs.com/jamesmile/archive/2010/04/17/1714311.html,在此感谢 C++中的operator new与new ope ...
- Python第二天 变量 运算符与表达式 input()与raw_input()区别 字符编码 python转义符 字符串格式化 format函数字符串格式化 帮助
Python第二天 变量 运算符与表达式 input()与raw_input()区别 字符编码 python转义符 字符串格式化 format函数字符串格式化 帮助 目录 Pychar ...
- C++内存管理(new operator/operator new/operator delete/placement new)
new operator 我们平时使用的new是new操作符(new operator),就像sizeof一样是语言内置的,不能改变它的含义,功能也是一样的 比如: string *ps = new ...
- Swift学习(一):自定义运算符 operator
自定义运算符仅能包含这些字符: / = - + * % < >!& | ^.~ 运算符位置: 前置运算符 prefix 中间运算符 infix 后置运算符 postfix 运算符其 ...
- 【转】C++易混知识点3. New Operator, Operator New, Placement New 实例分析,比较区别
我们知道,C++中引入了New 这个内置符号,很大方便了指针的使用,程序员不必关注与这块堆上新分配的内存是如何来的,如何初始化的,然后如何转换为我们想要的类型指针的.现在,我们重点来分析下这个NEW内 ...
- c++中new/operator new/placement new
1. new/delete c++中的new(和对应的delete)是对堆内存进行申请和释放,且两个都不能被重载. 2. operator new/operator delete c++中如果想要实现 ...
- 重载运算符-operator
先看段代码: struct node { friend bool operator< (node n1, node n2){ // 优先取最小的,它与下面的 // 是等价的 return n1. ...
- 操作符(运算符)重载 或者叫 二元运算符 operator + 与 转换式操作符 implicit operator explicit operator
static void Main(string[] args) { rational r1 = new rational(5); rational r2 = new rational(51); rat ...
- 运算符 Operator 及优先级
算数运算符 + - * / ** % /表示自然除,结果是浮点数.//为整除.python2.x版本/和//都是整除. 位运算符 & | ~ ^ << >> <& ...
随机推荐
- Office 2010 & SharePoint 2010 Service Pack 2现在可用啦
Access 2010 Runtime SP2 KB2687444 32-bit 64-bit Duet Enterprise for Microsoft SharePoint and SAP SP2 ...
- js实现form表单提交,图片预览功能
代码如下 <html> <head> <meta http-equiv="Content-Type" content="text/html; ...
- jQuery基础---Ajax基础教程(二)
jQuery基础---Ajax进阶 内容提纲: 1.加载请求 2.错误处理 3.请求全局事件 4.JSON 和 JSONP 5.jqXHR 对象 发文不易,转载请注明出处! 在 Ajax 基础一篇中, ...
- c#中的数据类型简介(string)
Sting 字符串 引入话题 字符串是一个引用类型,从string数据类型的代码定义中也可以看出它实现了IEnumerable<char>接口和IEnumerable接口,因此字符串可以看 ...
- DBubtil的使用
1.什么是O-R Mapping(对象-关系映射) 常用O-R Mapping映射工具 Hibernate(全自动框架) Ibatis(半自动框架/SQL) Commons DbUti ls(只是对J ...
- MySQL常用的指令
MySQL指令在网上百度出来的是一大堆,在此只是整理平时用的比较多的指令. 百度文库中的这篇文章可以参考http://wenku.baidu.com/view/b5e83a27ccbff121dd36 ...
- Jquery 解决 H5 placeholder元素问题
<style type="text/css"> .placeholder{ color: #cacaca; } </style> <script ty ...
- 利用C#轻松创建不规则窗体
1.准备一个不规则的位图 可以使用任意一种你喜欢的作图工具,制作一个有形状的位图,背景使用一种其他的颜色.这个颜色在编程中用得着,所以最好使用一种容易记忆的颜色.如黄色,文件名为bk.bmp 2.创建 ...
- linux ARP攻击处理
今天部门受到arp攻击 多说机器无法正常联网了,windows下的绑定下mac地址或者打开360arp防火墙就就ok了.我讲讲linux下的arp攻击的发现和处理吧.边学边讲,说的不对的欢迎大家指出, ...
- Linux Syslog
http://blog.chinaunix.net/uid-677314-id-164215.html http://blog.chinaunix.net/uid-24708340-id-397132 ...