条款49:了解new-handler的行为

考虑如下代码:

void outOfMem() {
    std::cerr << "unable to satisfy request for memory\n";
    std::abort();
}

int main() {
    std::set_new_handler(outOfMem);
    int *p = new int[1000000000000000]; //异常
    return 0;
}

operator new无法满足内存申请时,它会不断调用new-handler函数,直到找到足够的内存。

设计一个良好的new-handler函数必须做以下事情

  1. 让更多内存可被使用
  2. 安装另外一个new-handler
  3. 卸除new-handler
  4. 抛出bad_alloc
  5. 不返回

有时你想以不同的方式处理内存分配失败的情况:

class X {
	public:
		static void outOfMemory();
};

class Y {
	public:
		static void outOfMemory();
};

X *p1 = new X; // 如果分配不成功,调用X::outOfMemory
Y *p1 = new Y; // 如果分配不成功,调用Y::outOfMemory

解决办法是令每个class提供自己的set_new_hanlderoperator new

class Widget {
    public:
        static std::new_handler set_new_handler(std::new_handler p) throw();
        static void *operator new(std::size_t size) throw(std::bad_alloc);
    private:
        static std::new_handler currentHandler;
};

std::new_handler Widget::currentHandler = 0;
std::new_handler Widget::set_new_handler(new_handler p) throw()
{
    std::new_handler oldHandler = currentHandler;
    currentHandler = 0;
    return oldHandler;
}

最后,Widgetoperator new做以下事情

  1. 调用标准set_new_hanlder,告知Widge的错误处理函数
  2. 调用global operator new,执行实际的内存分配
  3. 如果global operator new能够分配足够一个Widget对象所用内存,Widgetoperator new会返回一个指针,指向分配所得

以一个资源管理类实现上述操作:

class NewHandlerHolder
{
public:
    explicit NewHandlerHolder(std::new_handler nh) : handler(nh){} // 取得目前的new-hanlder
    ~NewHandlerHolder()
    { std::set_new_handler(handler);}

private:
    std::new_handler handler;
    NewHandlerHolder(const NewHandlerHolder&); // 阻止copy
    NewHandlerHolder & operator =(const NewHandlerHolder &);
};

然后实现Widget的opeator new

void* Widget::operator new (std::size_t size) throw(std::bad_alloc)
{
    NewHandlerHolder h(std::set_new_handler(currentHandler)); // 安装Widget的new-handler
    return ::operator new(size);                             // 分配内存或抛出异常
}  

客户代码使用如下:

    Widget::set_new_handler(outOfMem); // 设定outOfMem为Widget的new-handing
    Widget* pw1 = new Widget;          // 如果内存分配失败调用outOfmem
    std::string* ps = new std::string; // 如果内存分配失败调用global new-hanlding函数
    Widget::set_new_handler(0);        // 设定Widget的new-handing为null
    Widget* pw2 = new Widget;          // 如果内存分配失败,立刻抛出异常
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值