了解new_handler

原创 2015年11月20日 12:37:37

了解new_handler

内存管理是C++的难点,也是重点,今天就把new_handler的学习笔记和大家分享。请大家多多指点。
参考书籍:《Effective C++》

关于new_handler

new_handler位于头文件< new >中
当new无法成功申请内存,在抛出异常之前,new会调用一个系统默认或用户指定的错误处理函数,也就是这里的new_handler。我们可以通过set_new_handler来设置我们的错误处理函数。

new_handler的定义

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

所以new_handler是一个函数指针。而set_new_handler是用来设置新的new_handler,后返回旧的new_handler的函数。

new_handler的简单使用实例

使用的是vs2015

#include <iostream>
#include <new>
#include <windows.h>

void OutOfMem() {
    std::cout << "内存空间不足" << std::endl;
    abort();
}

int main() {
    std::set_new_handler(OutOfMem);
    char *pint(new char[0x7fffffff]);
    return 0;
}

VS2015

当new发现没有足够内存空间时,调用new_handler指向的函数,打印出“内存空间不足”后 abort() 。如果没有 abort() 它的行为又是怎样的呢?

这里写图片描述

如图所示,他将会无止境的调用OutOfMem。当new无法满足内存申请的要求时,他会不断地调用new_handler,直至new找到一片足够大的内存返回为止。

为类设置自己的new_handler

为类实现自己的new_handler将通过重载 局部的new 实现。
看一个例子:

#include <iostream>
#include <new>
#include <windows.h>

//这里用于保存 默认的全局的new_handler,当该类的析构函数调用时,将handler还原
//相当于一个简易的GC
class HandlerHolder {
public:
    explicit HandlerHolder(std::new_handler nh) :handler(nh) {}
    ~HandlerHolder() { std::set_new_handler(this->handler); } //将保存的默认的全局handler还原
    HandlerHolder(const HandlerHolder&) = delete;  //阻止拷贝行为
    HandlerHolder&operator=(const HandlerHolder&) = delete;//阻止拷贝行为
private:
    std::new_handler handler;//保存 new_handler,这里用来保存全局的new_handler
};

class Demo {
public:
    static std::new_handler set_new_handler(std::new_handler nh) {
        std::new_handler oldhandler = cur_handler;
        cur_handler = nh;
        return oldhandler;
    }
    void * operator new(size_t size)throw(std::bad_alloc){
        HandlerHolder h(std::set_new_handler(cur_handler)); //handlerHolder 保存旧版的new_handler,
                                                            //当new结束时,handlerHolder的析构函数将被调用,
                                                            //new_handler将被还原为全局的new_handler
        return ::operator new(size);  //调用全局的new
    }
        void *operator new[](size_t size) {
        return operator new(size);
    }
private:
    static std::new_handler cur_handler;//保存当前的new_handler
};

std::new_handler Demo::cur_handler(nullptr);

void OutOfMem() {
    std::cout << "Run out of Men" << std::endl;
    abort();
}

int main() {
    Demo::set_new_handler(OutOfMem);
    Demo * p(new Demo[0x7fffffff]);
    //1.当new发生时,首先调用Demo的operator new[]跳转到operator new,这时在new函数中,new_handler被装载
    //2.如果new失败,将调用OutOfMen;如果new成功,将返回内存地址,HandlerHolder将被析构,在析构时调用set_new_handler
    //  还原装载OutOfMem之前的new_handler
    return 0;
}

这里写图片描述
在Demo::set_new_handler的参数中,我们可以传入各种自定义的内存分配失败的处理方法。在《Effective C++》中,为我们呈现了几种:

1.让更多的内存可以被使用(也就是清理内存,让出更多的空间给这里的内存分配操作)
2.安装另一个new_handler(当这个new_handler无法处理当前分配失败的情况时,我们可以装在另外一个new_handler试图处理这种情况)
3.卸载new_handler(如果当前的new_handler确实无法处理当前错误,那么就将当前的new_handler卸载,例如nullptr,让new抛出bad::alloc的异常)
4.直接抛出bad::alloc的异常
5.调用abort()或exit()直接终止程序

用继承和模板为类提供其独有的new_handler

#include <iostream>
#include <new>
#include <Windows.h>

//这里用于保存 默认的全局的new_handler,当该类的析构函数调用时,将handler还原
//相当于一个简易的GC
class HandlerHolder {
public:
    explicit HandlerHolder(std::new_handler nh) :handler(nh) {}
    ~HandlerHolder() { std::set_new_handler(this->handler); } //将保存的默认的全局handler还原
    HandlerHolder(const HandlerHolder&) = delete;  //阻止拷贝行为
    HandlerHolder&operator=(const HandlerHolder&) = delete;//阻止拷贝行为
private:
    std::new_handler handler;//保存 new_handler,这里用来保存全局的new_handler
};

template<typename T>class NewHandler {
public:
    static std::new_handler set_new_handler(std::new_handler nh) {
        std::new_handler oldhandler = cur_handler;
        cur_handler = nh;
        return oldhandler;
    }
    void *operator new(size_t size){
        HandlerHolder holder(std::set_new_handler(cur_handler));
        return ::operator new(size);
    }
        void *operator new[](size_t size) {
        return operator new(size);
    }
private:
    static std::new_handler cur_handler;
};

template<typename T>std::new_handler NewHandler<T>::cur_handler(nullptr);

class Demo :public NewHandler<Demo> {
public:
private:
    static std::new_handler cur_handler;//保存当前的new_handler
};

void OutOfMem() {
    std::cout << "Run out of Mem" << std::endl;
    abort();
}

int main() {
    Demo::set_new_handler(OutOfMem);
    Demo * p(new Demo[0x7fffffff]);
    return 0;
}

这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

《Effective C++》读书笔记之item49:了解new-handler的行为

1.new_handler函数:当operator new或operator new[]分配内存失败时调用的函数。 set_new_handler函数:试图分配更多内存以足够使用,成功时会返回,否则...

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

/*条款49:了解new-handler的行为*/ #include using namespace std; //operator new 当无法满足某一内在分配需求时,它会抛出异常,返回NULL指...
  • sbfksmq
  • sbfksmq
  • 2015年09月29日 12:49
  • 147

改善C++ 程序的150个建议学习之建议31:了解new_handler的所作所为

建议31:了解new_handler的所作所为 在使用operator new申请内存失败后,编译器并不是不做任何的努力直接抛出std::alloc异常,在这之前,它会调用一个错误处理函数(这个...

《Effective C++》:条款49:了解new-handler的行为

C++内存是由程序员手动管理的,不像Java或.net有垃圾回收机制。C++内存管理主要是分配例程和归还例程(allocation and deallocation routines),即operat...

C++ - 了解new_handler的所作所为

1. 在使用operator new申请内存失败后,编译器并不是不做任何的努力直接抛出std::bad_alloc异常,在这之前,它会调用一个错误处理函数(new_handler)。 2. ...
  • xsj1987
  • xsj1987
  • 2012年10月05日 20:20
  • 155

Effective C++ 3e----new & delete(八)条款49:了解new-handler的行为

当我看到C++ Primer 第五版中介绍new和operator操作符的时候我非常惊叹C++的强大功能,于是趁热打铁读了More Effective C++中关于new和delete操作的有关章...

C++箴言:理解 new-handler的行为

当 operator new 不能满足一个内存分配请求时,它抛出一个 exception(异常)。很久以前,他返回一个 null pointer(空指针),而一些比较老的编译器还在这样做。你依然能达到...

在子线程中new一个Handler

handler的作用是线程间通信 那么在子线程中new一个handler就是要有其他线程想要和他通信如果直接newThread thread=new Thread(){ @O...
  • yeyuyyy
  • yeyuyyy
  • 2016年10月24日 14:33
  • 1045

Set_New_Handler()

当运算符new找不到足够大的连续内存块来为对象分配内存时将会发生什么?一个称为 new-handler的函数被调用。 对于new-handler的缺省动作是抛出一个异常。然而,如果我们在程序里用堆分...

关于set_new_handler

当运算符new找不到足够大的连续内存块来为对象分配内存时将会发生什么?一个称为 new-handler的函数被调用。 对于new-handler的缺省动作是抛出一个异常。然而,如果我们在程序里用...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:了解new_handler
举报原因:
原因补充:

(最多只允许输入30个字)