C++中的new操作符首先使用operator new函数来分配空间,然后再在此空间上调用类的构造函数构造对象。当operator new无法分配所需的内存空间时,默认的情况下会抛出一个bad_alloc异常,在抛出这个异常之前,如果用户指定了错误处理函数即new_handler,则程序会先执行new_handler函数进行错误处理。为了设置这个错误处理函数,我们需要调用set_new_handler函数,它在std命名空间内的情况如下所示

namespace std{
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p)throw ();
}

  set_new_handler函数承若不抛出任何异常。该函数接受一个new_handler函数指针,且返回一个这样的指针。pNew代表的是如果operator new发生失败,采用的错误处理函数是pNew所指向的函数,set_new_handler函数返回的是以前的错误处理函数指针。比如,

void myErrorHandler(){
cerr<<"can't need the request for memory";
abort();
}
int main(){
std::set_new_handler(myErrorHandler);
int *ptr=new int[1000000000L];
delete [] ptr;
return ;
}

  当出现无法满足内存分配要求的时候,程序会不断的调用myErrorHandler函数进行内存的分配,如果错误处理函数中没有abort(),终端会不断的打印错误提示。设置全局的set_new_handler,只要出现operator new失败,都会调用该错误处理函数。但是如果我们需要给不同的类设置不同的错误处理函数时,该怎么办呢?也就是说我们需要定制类自己的set_new_handler函数。

class Widget{
public:
static std::new_handler set_new_handler(std::new_handler pNew) throw ();
static void* operator new(std::size_t size)throw (std::bad_alloc);
private:
static std::new_handler currentHandler;
int array[100000000L];//为了容易让new Widget出现异常
};
std::new_handler Widget::currentHandler=0;

  如上所示,类Widget需要定义自己的new_handler变量,而且需要定义自己的set_new_handler函数和operator new函数,set_new_handler函数比较简单,参照全局的set_new_handler函数的行为即可。

std::new_handler Widget::set_new_handler(std::new_handler pNew){
std::new_handler oldHandler=currentHandler;
currentHandler=pNew;
return oldHandler;
}

  函数set_new_handler设置新的new_handler,并且返回以前的new_handler。

  那么Widget类中的operator new函数应该怎么定义呢?

  首先,它应该设置本类的new_handler,怎么给Widget设置自己的new_handler并让其正常工作呢?调用std::set_new_handler即可,类中的currentHandler可作为其参数;

  其次,调用std::operator new函数请求分配内存,但是,这里可能存在一个资源泄露的问题,如第一步,我们将全局的set_new_handler设置成类Widget的错误处理函数,如果分配失败,我们怎么将原来的new_handler再设置回去呢?很显然的一种方法就是通过对象来管理new_handler,如下

  

class NewHandlerHolder{
public:
explicit NewHandlerHolder(new_handler p):oldHandler(p){}
~NewHandlerHoler(){
std::set_new_handler(oldHander);
}
private:
std::new_handler oldHandler;
NewHandlerHolder(const NewHandlerHolder&);
NewHandlerHolder& operator=(const NewHandlerHolder&);
};

  这是一个资源管理类,如果我们定义了一个NewHandlerHolder对象来管理原来的new_handler,当内存分配失败时,抛出异常且函数退栈,同时也会调用已经构造的对象的析构函数,当我们调用NewHandlerHolder的析构函数时,会重新将原来的new_handler设置回去。用于资源管理的类在较多情况下不允许进行赋值和复制构造的动作,因为我们希望这个资源管理的对象具有资源唯一的管理权。

  此时,我们就可以写出来Widget类中的operator new函数了。

void* Widget::operator new(std::size_t size) throw (std::bad_alloc){
NewHandlerHolder temp(std::set_new_handler(currentHandler));
return ::operator new(size);
}

  定义完所有所需的内容后,我们可以使用定制的new_handler。

int main(){
Widget::set_new_handler(myErrorHandler);
//Widget::set_new_handler(0);
while()
Widget *ptr=new Widget;
}

  运行结果如下图

  

  将注释的解注,运行结果没有"can't need the request for memory"。

  以上思想就能为各个类编写自己的定制的new_handler,但是为每个需要编写定制new_handler的类写如此相似的代码,似乎有点不合理,为了避免代码重复,我们可以使用模板

  

template<typename T>
class NewHandlerSupport{
public:
static std::new_handler set_new_handler(std::new_handler newHandler)throw ();
static void* operator new(std::size_t size)throw (std::bad_alloc);
private:
static std::new_handler currentHandler;
};
template<typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size){
NewHandlerHolder temp(std::set_new_handler(currentHandler));
return ::operator new(size);
}
template<typename T>
std::new_handler NewHandlerSupport<T>::set_new_handler(std::new_handler newHandler)throw(){
std::new_handler oldHander=currentHandler;
currentHandler=newHandler;
return oldHandler;
}
template<typename T>
std::new_handler NewHandlerSupport<T>::currentHandler=;

  如果我们希望类widget获得定制的new_handler行为,只需要将widget类以public继承NewHandlerSupport<widget>即可。我们只是希望获得不同模板参数所带来的不同的static std::new_handler currentHandler,我们需要用它来定制各个类的new_handler。

定制类自己的的new_handler的更多相关文章

  1. 【Python】[面向对象高级编程] 多成继承,定制类,使用枚举

    1.多成继承 class SmallDog(Animal,Dog) pass MixIn就是一种常见的设计. 2.定制类类似__slots__这种形如 __xxx__ 的变量或者函数名,在python ...

  2. python基础——定制类

    python基础——定制类 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方 ...

  3. python 定制类

    看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让cla ...

  4. python学习第十七天 --定制类

    何为定制类? Python的class允许定义许多特殊方法,可以让我们非常方便地生成特定的类.在类中应用或者重写python的特殊方法,得到的类,就是定制类. 大家都知道print的用法.见下面例子 ...

  5. Python面向对象高级编程-__slots__、定制类,枚举

    当在类体内定义好各种属性后,外部是可以随便添加属性的,Python中类如何限制实例的属性? Python自带了很多定制类,诸如__slots__,__str__ __slots__ __slots__ ...

  6. 快速了解Python的定制类

    多重继承 class Student(man,oldman): pass 可以继承多个父类,拥有他们的方法,如果有父类有相同的方法,哪个在前用哪个 定制类 看到类似__slots__这种形如 __xx ...

  7. python面向对象高级:定制类

    Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类. 比如: __str__ 与__repr____iter____getitem____call__ __str__ 与__r ...

  8. python定制类详解

    1.什么是定制类python中包含很多内置的(Built-in)函数,异常,对象.分别有不同的作用,我们可以重写这些功能. 2.__str__输出对象 class Language(object): ...

  9. Python定制类(进阶6)

    转载请标明出处: http://www.cnblogs.com/why168888/p/6411919.html 本文出自:[Edwin博客园] Python定制类(进阶6) 1. python中什么 ...

随机推荐

  1. IE8下解决position:flxed无效的问题

    只需将文档类型声明改成如下方式即可 <!DOCTYPE html>

  2. 关于Redis中的serverCron

    1.serverCron简介 在 Redis 中, 常规操作由 redis.c/serverCron 实现, 它主要执行以下操作 /* This is our timer interrupt, cal ...

  3. 在VS2010中使用Outlook工具栏

    参考资料:微软MSDN.VS2010示例代码 一开始上段子总是能活跃气氛,等哪天我再打开自己的这篇博客,总是能够让自己傻傻的乐一下. 我一女同学,毕业去一大公司应聘,竞争很激烈,最后剩下她和一位女士. ...

  4. 快速解决mysql Lost connection to MySQL server at 'reading initial communication packet及can't connect to mysql server on 'localhost'

    今天在使用Navicat连一个远程mysql时,总是提示连接不成功,提示Lost connection to MySQL server at 'reading initial communicatio ...

  5. Mongo 的相关增删改查

    1,Mongod 下载安装,请看https://www.mongodb.com/download-center 2,插入语句: MongoDB后台管理 Shell 如果你需要进入MongoDB后台管理 ...

  6. Sublime text3中配置Github

    一.Git安装 到Git的 官网 上去下载相应环境的Git安装文件. 我的是win10,安装到D:\ProgramFiles\Git,在桌面右键出现下面两个红色框框就可以了. 二.Git配置及生成密钥 ...

  7. jquery获取复选框(checkbox)的选中值(一组和单个)

    使用jquery获取一组或者单个checkbox的选中状态的值.下面通过一个示例进行说明,假设现有一页面有一组checkbox的name的值为id,那么获取这组name=id的checkbox的值的方 ...

  8. xamarin.android 给View控件 添加数字提醒效果-BadgeView

    本文代码从java项目移植到.net项目   java开源项目:https://github.com/jgilfelt/android-viewbadger using System; using S ...

  9. 探索 OpenStack 之(14):OpenStack 中 RabbitMQ 的使用

    本文是 OpenStack 中的 RabbitMQ 使用研究 两部分中的第一部分,将介绍 RabbitMQ 的基本概念,即 RabbitMQ 是什么.第二部分将介绍其在 OpenStack 中的使用. ...

  10. [转]用NPOI操作EXCEL--数据有效性

    本文转自:http://www.cnblogs.com/atao/archive/2009/09/22/1572170.html 在有些情况下(比如Excel引入),我们可能不允许用户在Excel随意 ...