定制类自己的的new_handler

  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(1)
        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=0;

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

时间: 2024-10-06 02:42:39

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

类的内建函数和用来定制类的特殊方法

两个类的内建函数一:isinstance() 1 class P1(): 2 3 def __init__(self, name): 4 self.name = name 5 pass 6 7 class P2(P1): 8 A = P1('wang') # 定义类属性!! 9 B = P1('zi') 10 11 print(P2.__dict__) 12 for i, v in P2.__dict__.items(): 13 if i =='A': 14 print(v) 15 print(

python 定制类

看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函数. 除此之外,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类. __str__ 我们先定义一个Student类,打印一个实例: >>> class Student(object): ... def __init__(self, name):

【转载】定制类

原文链接:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319098638265527beb24f7840aa97de564ccc7f20f6000 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函

Python学习之定制类

本文和大家分享的主要是 python开发中定制类的相关内容,一起来看看吧,希望对大家学习和使用这部分内容有所帮助. 1. python中什么是特殊方法 任何数据类型的实例都有一个特殊方法:  __str__() ·  用于 print 的  __str__ ·  用于 len 的  __len__ ·  用于 cmp 的  __cmp__ ·  特殊方法定义在 class 中 ·  不需要直接调用 · Python 的某些函数或操作符会调用对应的特殊方法 file:///C:\Users\wlc

MyPython--&gt;进阶篇--&gt;定制类

多重继承 class Student(man,oldman): pass 可以继承多个父类,拥有他们的方法,如果有父类有相同的方法,哪个在前用哪个 定制类 看到类似__slots__这种形如 __xxx__的变量或函数名就要注意,这些在python中是有特殊用途的 我们已经知道了__slots__的用法,用__len__()方法我们也知道是为了能让class作用于len()函数 __str__ 我们先定义一个Student类,打印一个实例 class Studentc(): def __init

二十五 定制类

看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函数. 除此之外,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类. __str__ 我们先定义一个Student类,打印一个实例: >>> class Student(object): ... def __init__(self, name):

python中的定制类(转载)

body { font-family: 微软雅黑,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLiU,serif; font-size: 10.5pt; line-height: 1.5; } html, body { } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bold; } h3 { fon

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

何为定制类? Python的class允许定义许多特殊方法,可以让我们非常方便地生成特定的类.在类中应用或者重写python的特殊方法,得到的类,就是定制类. 大家都知道print的用法.见下面例子 >>> lst = [2,3,4] >>> print lst [2, 3, 4] >>> class Animal(object): pass >>> a = Animal() >>> print a <__ma

Python 面向对象高级编程——定制类

1.1   定制类 1.1.1   __str__ >>> class Student(object): ...    def __init__(self, name): ...        self.name = name ... >>> s = Student('daidai') >>> s.name 'daidai' >>> Student('daidai').name 'daidai' >>> print(