需要搞清楚空间配置器之前必须分清楚C++中各种内存分配和释放的区别?
这里的问题就是当new分配内存失败该怎么办?
现在讨论的方法,在STL内存分配中使用了很多。
new是通过调用对应的operator new产生的内存,并且operator new可以重载。C++采取的做法就是通过new-handler回调函数处理。当operator new不能满足分配需求时候,在抛出对应异常之前会调用客户先前指定的new-handler回调函数。
1、设定全局的operator new对应的new-handler回调函数
void NoMoreMemory()
{
cerr << "Unable to satisfy memory"<<endl;
abort();
}
int main(void)
{
set_new_handler(NoMoreMemory);//设定<new>里面的全局handler函数
int *pBigData = new int[10000000000000];//分配失败调用回调函数。
return 0;
}
2、处理针对某个类分配失败的new-handle
例如我需要实现这种结果,X和Y全部都是自己定义的类,当new X失败时候,调用一个X对应的new-handle函数;当new Y失败的时候,调用Y对应的new-handle函数。实现这种功能就是重载operator new和set_new_handler函数,并在重载的函数里面调用<new>
头文件里面对应的operator new和set_new_handler函数。
class X{
private:
int x;
static new_handler currentHandler;//静态声明
public:
static new_handler set_new_handler(new_handler handler);//重载set_new_handler
static void *operator new[](size_t size);//重载operator new[],为了分配数组
};
new_handler X::currentHandler = 0;//默认定义并初始化为0
new_handler X::set_new_handler(new_handler handler){//定义静态
new_handler oldHandler = currentHandler;//保存当前Handler
currentHandler = handler;//重新设定当前handler
return oldHandler;//返回上一次使用的handler
}
void *X::operator new[](size_t size){//定义静态
//当new的时候使用
cout << "x test" << endl;
new_handler globleHandler = std::set_new_handler(currentHandler);//设定X对应的handler并保存系统全局handler
void *memory;
try{
memory = ::operator new[](size);//使用全局分配
}
catch(std::bad_alloc&){//分配失败
std::set_new_handler(globleHandler);//恢复全局handler
throw;
}
std::set_new_handler(globleHandler);//分配成功,恢复全局
return memory;//将对应首地址返回
}
class Y{
private:
int y;
static new_handler currentHandler;//静态声明
public:
static new_handler set_new_handler(new_handler handler);//重载set_new_handler
void *operator new[](size_t size);//重载operator new[],可以分配数组
};
new_handler Y::currentHandler = 0;//默认定义并初始化为0
new_handler Y::set_new_handler(new_handler handler){//定义静态
new_handler oldHandler = currentHandler;//保存当前Handler
currentHandler = handler;//重新设定当前handler
return oldHandler;//返回上一次使用的handler
}
void *Y::operator new[](size_t size){//定义静态
//当new的时候使用
cout << "y test" << endl;
new_handler globleHandler = std::set_new_handler(currentHandler);//设定X对应的handler并保存系统全局handler
void *memory;
try{
memory = ::operator new[](size);//
}
catch(std::bad_alloc&){//分配失败
std::set_new_handler(globleHandler);//恢复全局handler
throw;
}
std::set_new_handler(globleHandler);//分配成功,恢复全局
return memory;//将对应首地址返回
}
int main(void)
{
X::set_new_handler(NoMoreMemoryX);//设定X对应的handler
X *xBigData = new X[10];
Y::set_new_handler(NoMoreMemoryY);//设定X对应的handler
Y *yBigData = new Y[10000000000000];
return 0;
}
X和Y类通过重载operator new[]来实现类别数组的分配。set_new_handler
中设定设定currentHandler
,并记录上一次handler
。operator new[]
中设定currentHandler
,并在分配成功或者失败后恢复先前的handler
。总体设计思路就是通过保存和恢复机制,利用全局的set_new_handler和operator new[]
实现每个类对应的new-handler
。
3、设计NewHandleSupport类
从上面可以看出X和Y中关于new-handle的处理很类似,所以可以使用模板,使得代码重复率更加高。为什么将NewHandleSupport模板类?首先类全部是静态成员,假如不是模板,那么继承下来的静态成员也只有一份拷贝,导致X和Y不能有独自的
currentHandler
成员,所以可以通过定义模板类,使得每个X都有独自的currentHandler
。这真是很聪明的机制啊。设计一个NewHandleSupport模板,并将X类继承NewHandleSupport<X>
,那么就可以继承对应的功能。通过模板增加了代码的可重用性。设计模板仅仅是为了让每个子类都拥有对应的成员函数。
template <typename T>//定义模板
class NewHandlerSupport{
private:
static new_handler currentHandler;//静态声明
public:
static new_handler set_new_handler(new_handler handler);//重载set_new_handler
static void *operator new[](size_t size);//重载operator new[],为了分配数组
};
template <typename T>
new_handler NewHandlerSupport<T>::currentHandler = 0;//默认定义并初始化为0
template <typename T>
new_handler NewHandlerSupport<T>::set_new_handler(new_handler handler){//定义静态
new_handler oldHandler = currentHandler;//保存当前Handler
currentHandler = handler;//重新设定当前handler
return oldHandler;//返回上一次使用的handler
}
template <typename T>
void *NewHandlerSupport<T>::operator new[](size_t size){//定义静态
cout << "x test" << endl;
new_handler globleHandler = std::set_new_handler(currentHandler);//设定X对应的handler并保存系统全局handler
void *memory;
try{
memory = ::operator new[](size);//使用全局分配
}
catch(std::bad_alloc&){//分配失败
std::set_new_handler(globleHandler);//恢复全局handler
throw;
}
std::set_new_handler(globleHandler);//分配成功,恢复全局
return memory;//将对应首地址返回
}
class X:public NewHandlerSupport<X>{
public:
int x;
};
class Y:public NewHandlerSupport<Y>{
public:
int y;
};
int main(void)
{
new_handler oldHandler;
//set_new_handler(NoMoreMemory);//设定全局handler
X::set_new_handler(NoMoreMemoryX);//设定X对应的handler
X *xBigData = new X[10];
Y::set_new_handler(NoMoreMemoryY);//设定X对应的handler
Y *yBigData = new Y[10000000000000];
int *pBigData = new int[10000000000000];
return 0;
}