`
kmplayer
  • 浏览: 498379 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

条款7:为内存不足的情况预做准备.

 
阅读更多
1,当operator new无法满足内存需求时,抛出std::bad_alloc.
下面是一个验证的代码:
#include <iostream>
#include <stdexcept>
using namespace std ;

int main ()
{
    try
    {
        int* p=NULL;
        while(1)
            p=new int[10000];
    }catch(std::bad_alloc&)
    {
        cout<<"no enough mem."<<endl;
    }
	return 0 ;
}


2,C++的一个公约:
当operator new无法满足需求时,它会在抛出exception前先调用一个专属的错误处理函数.
我们称之为:new-handler.

3,当operator无法满足内存需求时,它会不只一次的调用new-handler函数;
它会不断的重复调用,直到找到足够的内存.
一个设计良好的new-handler函数必须完成下面几件事:
(1)让更多内存可用.
例如:事先在程序起始处配置一大块内存,然后在new-handler第一次被调用时释放之.
(2)配置另外一个new-handler,其手上握有比较多的资源.
(3)卸除new-handler,set_new_handler(NULL)
将不再调用专属函数,而直接抛出exception.
(4)抛出exception.
(5)不回返,直接调用abort()或exit.
#include <iostream>
#include <stdexcept>
using namespace std ;

void noMoreMemory()
{
    cout<<"Unable to satify request for memory."<<endl;
    //原则(5):不回返
    abort();//不加,将会是一个死循环.
    //原则(4):也可以通过抛出一个异常
    //throw std::bad_alloc();
}

int main ()
{
    //typedef void (*new_handler)();  头文件中已经给出
    //设定自己的专属错误处理函数.
    //返回之前的new_handler
    new_handler old_new_handler=set_new_handler(noMoreMemory);
    //set_new_handler(NULL); //卸除new-handler,抛出异常.
    try
    {
        int* p=NULL;
        while(1)
            p=new int[10000];
    }catch(std::bad_alloc&)
    {
        cout<<"no more memory."<<endl;
        set_new_handler(old_new_handler);
    }
    set_new_handler(old_new_handler);
	return 0 ;
}

4,设定类class专属的new-handler.
一个强大的类模板.
#include <iostream>
#include <stdexcept>
using namespace std ;

template<class T>
class NewHandlerSupport
{
public:
    static new_handler set_new_handler(new_handler p);
    static void* operator new(size_t size);
    static void* operator new[](size_t size);
private:
    static new_handler currentHandler;
};

template<class T>
new_handler NewHandlerSupport<T>::set_new_handler(new_handler p)
{
    new_handler oldHandler=currentHandler;
    currentHandler=p;
    return oldHandler; //返回之前的专属函数
}

template<class T>
void* NewHandlerSupport<T>::operator new(size_t size)
{
    //下面调用标准的set_new_handler
    new_handler globalHandler=std::set_new_handler(currentHandler);

    void* memory;
    try
    {
        //使用标准的new.
        memory=::operator new(size);
    }catch(std::bad_alloc)
    {
        std::set_new_handler(globalHandler);
        throw; //继续抛出异常
    }


    std::set_new_handler(globalHandler); //返回原来的设置
    return memory; //返回之前的专属函数
}

template<class T>
static void* NewHandlerSupport<T>::operator new[](size_t size)
{
    return operator new(size);
}

template<class T>
new_handler NewHandlerSupport<T>::currentHandler; //设置为0

void noMoreMemory()
{
    cout<<"Unable to satify request for memory."<<endl;
    //abort();
    throw std::bad_alloc();
}

class X : public NewHandlerSupport<X>
{
};

int main ()
{
    X::set_new_handler(noMoreMemory);
    try
    {
        X* p=NULL;
        //先调用专属函数,然后有专属函数抛出异常.
        while(1)
            p=new X[100000];
    }catch(std::bad_alloc&)
    {
        cout<<"no more memory."<<endl;
    }

    X::set_new_handler(0);
    try
    {
        X* p=NULL;
        //不再调用专属函数,直接捕获异常.
        while(1)
            p=new X[100000];
    }catch(std::bad_alloc&)
    {
        cout<<"no more memory."<<endl;
    }
	return 0 ;
}

5,旧的编译器:
如果内存配置失败不会抛出异常,只是返回0.
测试实例:
int* p=new (nothrow)int;
if(p==0)
cout<<"memory error;"<<endl;
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics