new、operator new、placement new
首先我们区分下几个容易混淆的关键词:
new、operator new、placement new
new和delete操作符我们应该都用过,它们是对堆中的内存进行申请和释放,而这两个都是不能被重载的。要实现不同的内存分配行为,需要重载operator new,而不是new和delete。
operator new
(1) 只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则
->如果有new_handler,则调用new_handler,否则
->如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则
->返回0
(2) 可以被重载
但是不能在全局对原型为void operator new(size_t size)这个原型进行重载,
一般只能在类中进行重载。如果类中没有重载operator new,
那么调用的就是全局的::operator new来完成堆的分配。
同理,operator new[]、operator delete、operator delete[]也是可以重载的。
(3) 重载时,返回类型必须声明为void*
(4) 重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t
(5) 重载时,可以带其它参数
new(也称作new operator) () 调用operator new分配足够的空间,并调用相关对象的构造函数
() 不可以被重载
placement new 是重载operator new的一个标准、全局的版本。它不能被自定义的版本代替(不像普通的operator new和operator delete能够被替换成用户自定义的版本)。它的原型如下:
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
placement new,只是operator new的一个重载的版本,只是我们很少用到它。如果你想在已经分配的内存中创建一个对象,使用new时行不通的。也就是说placement new允许你在一个已经分配好的内存中(栈或者堆中)构造一个新的对象。原型中void*p实际上就是指向一个已经分配好的内存缓冲区的的首地址。
我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。placement new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行,不需要查找内存,内存分配的时间是常数。而且不会出现在程序运行中途出现内存不足的异常。所以,placement new非常适合那些对时间要求比较高,长时间运行不希望被打断的应用程序。 placement new使用方法如下:
1)分配内存
memset( buff, 0, sizeof(Foo));
栈上:
char buf[ sizeof(Foo) ]={0};
2)构建对象
3)使用对象
pfoo->set_f(1.0f);
pfoo->get_f();
4)析构对象,显式的调用类的析构函数。
5)销毁内存
placement new的好处:
1)在已分配好的内存上进行对象的构建,构建速度快。
2)已分配好的内存可以反复利用,有效的避免内存碎片问题。
Placement new的标准用法:
#include <iostream>
using namespace std; class Foo
{
char cc;
float f; public:
void print() { std::cout << "ADDR: " << this << std::endl; }
void set_f( float _f ) { std::cout << "set f val : " << _f << std::endl; f = _f; }
void get_f() { std::cout << "get f val : " << f << std::endl; }
~Foo(){ cout <<"~Foo()"<<endl; }
};
int main()
{
char* buff = new char[ sizeof(Foo) ];
memset( buff, , sizeof(Foo) ); Foo *pfoo = new (buff)Foo; pfoo->print();
pfoo->set_f( 1.0f );
pfoo->get_f(); pfoo->~Foo(); delete [] buff;
return ;
}
placement new还可以解决的一个问题是建立带参数的构造函数对象数组
#include <iostream>
using namespace std;
class CPong
{
public:
CPong( int m ) : v(m) { std::cout << "CPong ctor." << std::endl; } private:
int v;
}; int main()
{
char* pong = new char[ sizeof(CPong) * 10 ];
CPong* pp = (CPong*)pong; for ( int i=0; i<10; ++i )
{
new (pp+i)CPong(i);
} for ( int j=0; j<10; ++j )
{
pp[j].~CPong();
} delete [] pong;
return 0;
}
注意:
在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释放空间,但必须调用析构函数销毁对象。
参考自:http://www.ksarea.com/articles/20080124_cc.html
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;
}
重载operator new
class Base {
public:
Base() { }
void *operator new( size_t size, string str ) {
cout << "Logging an allocation of " << size << " bytes for new object'" << str << "'" << endl;
return malloc( size );
}
int var;
double var2;
};
...
Base* b = new ("Base instance 1") Base;
new operator的四种用法
pointer = new type;
pointer = new type( initializer );
pointer = new type[size];
pointer = new( arg-list ) type... //4th vision Foo *foo;
foo = new(nothrow) Foo(); //use the 4th vision
assert( foo );
其中,nothrow为 C++预定义的std::nothrow_t类型全局常量。
operator new可以被重载,它的三个版本本质上是函数,它们只分配空间,不调用构造函数。而new、delete(也叫做new operator、delete operator)不可被重载,它们是运算符,分配空间,并且调用构造函数。
new、operator new、placement new的更多相关文章
- 浅谈new operator、operator new和placement new 分类: C/C++ 2015-05-05 00:19 41人阅读 评论(0) 收藏
浅谈new operator.operator new和placement new C++中使用new来产生一个存在于heap(堆)上对象时,实际上是调用了operator new函数和placeme ...
- new 、operator new 和 placement new
一.原生operator new 我们先从原生operator new开始.考虑如下代码,它用来分配5个int型的空间并返回指向他们的指针[1]: int* v = static_cast<in ...
- [C++空间分配]new运算符、operator new、placement new的区别于联系
先科普一下: 1. new的执行过程: (1)通过operator new申请内存 (2)使用placement new调用构造函数(内置类型忽略此步) (3)返回内存指针 2. new和malloc ...
- 小结:c++中的new、operator new和placement new
小结:c++中的new.operator new和placement new new(也称作new operator),是new 操作符,不可重载 class T{...}; T *t = new T ...
- C++ 中 new 操作符内幕:new operator、operator new、placement new
一.new 操作符(new operator) 人们有时好像喜欢有益使C++语言的术语难以理解.比方说new操作符(new operator)和operator new的差别. 当你写这种代码: st ...
- C++中的new、operator new与placement new
转:http://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html new/delete与operator new/operator ...
- c++中的new、operator new、placement new
一.定义 1.new new是c++中的关键字,,其行为总是一致的.它先调用operator new分配内存,然后调用构造函数初始化那段内存. new 操作符的执行过程:1. 调用operator n ...
- C++ new operator, delete operator, operator new, operator delete, new placement
http://www.younfor.com/cpp-new-placement-new-operator-new.html http://www.cnblogs.com/luxiaoxun/arch ...
- C++中的new,operator new与placement new
以下是C++中的new,operator new与placement new进行了详细的说明介绍,需要的朋友可以过来参考下 new operator/delete operator就是new和 ...
随机推荐
- Hcharts和Echarts----制作报表的工具
Hcharts官网:https://www.hcharts.cn/Hcharts API文档:https://api.hcharts.cn/highcharts Echarts官网:http://ec ...
- 调整KVM虚拟机硬盘大小
KVM虚拟机的硬盘映像默认存放在“/var/lib/libvirt/images/”中,先查看你的硬盘映像格式是不是RAW格式: qemu-img info /var/lib/libvirt/imag ...
- Friendship POJ - 1815 基本建图
In modern society, each person has his own friends. Since all the people are very busy, they communi ...
- 转载《mysql 一》:mysql的select查询语句内在逻辑执行顺序
原文:http://www.jellythink.com/archives/924 我的抱怨 我一个搞应用开发的,非要会数据库,这不是专门的数据库开发人员干的事么?话说,小公司也没有数 据库开发人员这 ...
- PHP扩展--Yaf框架安装
安装/配置 编译安装 wge thttp://pecl.php.net/get/yaf-2.3.5.tgz tar -zxvfyaf-2.3.5.tgz cd yaf-2.3.5/ cd extens ...
- ReaderWriterLockSlim 类
今天在看Nop源码时,PluginManager中用到了ReaderWriterLockSlim类,于是简单做个笔记. ReaderWriterLockSlim 表示用于管理资源访问的锁定状态,可实现 ...
- git设置免密码登录
设置用户名和邮箱 git config --global user.name "<username>" git config --global user.email & ...
- ssh连接提示 "Connection closed by remote host"
如果原来是可以用ssh连接的, 突然连接不上通常是连接数过多导致的. 解决方法一. 把SSH连接数改大 修改服务器上的这个文件:/etc/ssh/sshd_config 找到这行: # MaxSess ...
- [LA3135]node形式的优先队列
n个触发器,每个触发器每period秒就产生一个编号为qnum的事件,求前k个事件. n<=1000 k<=10000 node形式的优先队列 主要在于重载小于号,确定优先顺序. #in ...
- PHP正则 贪婪匹配与非贪婪匹配
$str = ".abcdeabcde"; preg_match('/a.+?e/', $str, $match); print_r($match); Array ( [0] =& ...