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. 【体系结构】Oracle参数介绍

    [体系结构]Oracle参数介绍 1  BLOG文档结构图 2  前言部分 2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩ ...

  2. Struts中的OGNL和EL表达式笔记

    Struts中的OGNL和EL表达式笔记 OGNL(Object-Graph Navigation Language),可以方便的操作对象属性的表达式语言. 1.#符号的用途 一般有三种方式: 1.1 ...

  3. 读书笔记——Windows环境下32位汇编语言程序设计(13)关于EXCEPTION_DEBUG_INFO结构体

    在动手自己尝试编写书上第13章的例子Patch3时,遇到了一个结构体EXCEPTION_DEBUG_INFO. 这个结构体在MASM的windows.inc中的定义和MSDN中的定义不一样. (我使用 ...

  4. 第一章 Mysql 简介及安装和配置

    Mysql是最流行的关系型数据库管理系统,在WEB应用方面MySQL是最好的RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一. ...

  5. GMT与UTC简介

    一.简介 许多人都知道两地时间表简称为GMT或UTC,而世界时区表则通称为World Time ,那么GMT与UTC的实质原意又是为何?世界时区又是怎么区分的?面盘上密密麻麻的英文单字代表着什么意义与 ...

  6. APP 接口开发及读取静态缓存

    <?php /** * Description: App 接口 * Create date:2015-10-19 13:36 * Author: zhaoyingnan **/ class Re ...

  7. 迅为iTOP-4412嵌入式开发板实现中断驱动例程

    本文转自迅为:www.topeetboard.com 大家好,今天我们来学习一下 linux 中断处理驱动的编写,本节我们实现的功能是通过开发板上的按键来控制 led 发光二极管,在之前的章节我们学习 ...

  8. jemter的使用(三)

    前面的文章已经把接口请求.响应等前序工作做好,那么如何施加压力呢,看下面 1.点击线程组,设置线程属性,其中:线程数即并发用户数,ramp-up period是多长时间初始化上面的并发用户数,循环次数 ...

  9. 2014 Super Training #6 G Trim the Nails --状态压缩+BFS

    原题: ZOJ 3675 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3675 由m<=20可知,可用一个二进制数表 ...

  10. Win8/8.1 .NET3.5安装失败

    .NetFramework 作为开发人员,很多情况都需要.NetFramework,在Win7及之前的系统上直接双击 .NetFramework的安装包就可安装了. Win8/8.1无法安装.Net3 ...