C++为class设置专属的new_handler

本文详细介绍了C++中内存分配失败时如何通过new_handler来处理,包括如何设置和使用new_handler,以及如何实现自定义的new_handler来解决内存不足的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        当operator new无法满足某一内存分配需求时,它会抛出一个异常,以前它会返回一个null指针。在operator new抛出异常之前,它会调用客户指定的错误处理函数,即new_handler。为了指定这个用以处理内存不足的函数,客户必须调用set_new_handler,那是声明于<new>的一个标准程序库:   

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

        当operator new无法满足内存申请时,它会不断调用new_handler函数,就像下面的伪码这样:

    void* operator new(std:size_t size) throw(std::bad_alloc)
    {
        using namespace std;
        if(size = =0)
        {
            size = 1;
        }
        while(true)
        {
            void* result = malloc(size);
            if(result != NULL)
                 return result;
            new_handler globalHandler = set_new_handler(0);
            set_new_handler(globalHandler);
            if(globalHandler)  (*globalHandler)();
            else throw std::bad_alloc();
         }
    }

        一个设计良好的new_handler函数必须做以下事情:

        1、让更多的内存可被使用。这便造成operator new内的下一次内存分配动作可能成功。实现此策略的一个做法是,程序一开始执行就分配一大块内存,而后当new_handler第一次被调用,将它们释还给程序使用。

        2、安装另一个new_handler。如果目前这个new_handler无法取得更多更多可用的内存,或许它知道另外哪个new_handler有此能力。果真如此,目前这个new_handler就可以安装另外那个new_handler以替换自己。下次当operator new调用new_handler,调用的将是最新安装的那个。

        3、卸除new_handler,也就是将null指针传给set_new_handler。一旦没有安装任何new_handler,operator new会在内存分不足时抛出异常。

        以上是new_handler和set_new_handler相关知识,要实现class专属之new_handler,只需令每一个class提供自己的set_new_handler和operator new即可。假设你打算处理Widget class内存分配失败情况,你的class定义看起来像是这样:

class Widget{
public:
     static std::new_handler set_new_handler(sed:new_handler p) throw();
     static void* operator(std::size_t size) throw(std::bad_alloc);
private:
     static std::new_handler currentHandler;
};
        Widget的operator new做以下事情:

        1、调用标准的set_new_hander,将Widget的new_handler安装为global new_handler。

        2、调用global operator new,执行实际内存之分配。如果分配失败,global operator new会调用Widget的new_handler。如果global operator new最终无法分配足够内存,会抛出一个异常。在此情况下Widget的operator new必须恢复原本的global new_handler,然后再传播异常。为确保原本的new_handler总能够被重新安装回去,Widget将global operator new视为资源并用资源管理对象防止资源泄露。

        3、如果global operator new能够分配足够一个Widget对象所用内存,Widget的operator new将返回一个指针,指向分配所得。Widget的析构函数把Widget的operator new被调用前的那个global operator new恢复回来。

        下面是将global operator new作为资源进行管理的资源管理类:

class NewHandlerHolder{
public:
    explicit NewHandlerHolder(std::new_handler nh): handler(nh){}
    ~NewHandlerHolder()
    {
        set::set_new_handler(handler);
    }
private:
    std::new_handler handler;
};
         这样Widget的operator new实现相当简单:

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值