c++ new 用于动态分配内存。比如 A* a=new A();其实这里一共有三步:
1、分配sizeof(A)的内存,这里的分配是通过operator new(std::size_t)实现的
2、在分配的内存上初始化,调用A的构造函数
3、返回相应指针
某些时候我们需要重载operator new来达到一些目的,如内存泄漏检查。
一、operator new重载
需要注意几个问题:
1、应该实现handle_new,即分配内存不成功时的措施。
2、第一个参数应该是std::size_t
3、一般不重载placement new,placement new本身就是operator new的一种标准重载形式
4、重载operator new后要实现相应的operator delete,不过只有分配内存失败时才会调用重载的delete,或者还是会调用全局delete
重载实例
#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); } void operator delete(void* pointee) { cout<<"operator delete"<<endl; ::operator delete(pointee); } private: int num; }; int main() { X *px = new("A new class") X; delete px; return 0; }
二、placement new
placement new可以在指定的内存空间上构造对象,它的原型为:
void * operator new(std::size_t,void *p){ return p; }
使用方式如下:
new(ptr) A();其中ptr为已分配好的内存。
Placement new使用步骤
在很多情况下,placement new的使用方法和其他普通的new有所不同。这里提供了它的使用步骤。
第一步 缓存提前分配
有三种方式:
1.为了保证通过placement new使用的缓存区的memory alignment(内存队列)正确准备,使用普通的new来分配它:在堆上进行分配
class Task ;
char * buff = new [sizeof(Task)]; //分配内存
(请注意auto或者static内存并非都正确地为每一个对象类型排列,所以,你将不能以placement new使用它们。)
2.在栈上进行分配
class Task ;
char buf[N*sizeof(Task)]; //分配内存
3.还有一种方式,就是直接通过地址来使用。(必须是有意义的地址)
void* buf = reinterpret_cast<void*> (0xF00F);
第二步:对象的分配
在刚才已分配的缓存区调用placement new来构造一个对象。
Task *ptask = new (buf) Task
第三步:使用
按照普通方式使用分配的对象:
ptask->memberfunction();
ptask-> member;
//...
第四步:对象的析构
一旦你使用完这个对象,你必须调用它的析构函数来毁灭它。按照下面的方式调用析构函数:
ptask->~Task(); //调用外在的析构函数
第五步:释放
你可以反复利用缓存并给它分配一个新的对象(重复步骤2,3,4)如果你不打算再次使用这个缓存,你可以象这样释放它:delete [] buf;
三、operator new[]
new[]和new类似,仍然会优先调用类中重载的operator new[]。另外还要注意的是,在operator new[](size_t size)中传入的并不是sizeof(A)*num。而要在对象数组的大小上加上一个额外数据,用于编译器区分对象数组指针和对象指针以及对象数组大小。