new失败如何处理

需要搞清楚空间配置器之前必须分清楚C++中各种内存分配和释放的区别?

这里的问题就是当new分配内存失败该怎么办?

现在讨论的方法,在STL内存分配中使用了很多。
new是通过调用对应的operator new产生的内存,并且operator new可以重载。C++采取的做法就是通过new-handler回调函数处理。当operator new不能满足分配需求时候,在抛出对应异常之前会调用客户先前指定的new-handler回调函数。

1、设定全局的operator new对应的new-handler回调函数

void NoMoreMemory()
{
    cerr << "Unable to satisfy memory"<<endl;
    abort();
}
int main(void)
{
    set_new_handler(NoMoreMemory);//设定<new>里面的全局handler函数
    int *pBigData = new int[10000000000000];//分配失败调用回调函数。
    return 0;
}

这里写图片描述

2、处理针对某个类分配失败的new-handle

例如我需要实现这种结果,X和Y全部都是自己定义的类,当new X失败时候,调用一个X对应的new-handle函数;当new Y失败的时候,调用Y对应的new-handle函数。实现这种功能就是重载operator new和set_new_handler函数,并在重载的函数里面调用<new>头文件里面对应的operator new和set_new_handler函数。

class X{
private:
    int x;
    static new_handler currentHandler;//静态声明
public:
    static new_handler set_new_handler(new_handler handler);//重载set_new_handler
    static void *operator new[](size_t size);//重载operator new[],为了分配数组

};
new_handler X::currentHandler = 0;//默认定义并初始化为0
new_handler X::set_new_handler(new_handler handler){//定义静态
    new_handler oldHandler = currentHandler;//保存当前Handler
    currentHandler = handler;//重新设定当前handler
    return oldHandler;//返回上一次使用的handler
}
void *X::operator new[](size_t size){//定义静态
//当new的时候使用
    cout << "x test" << endl;
    new_handler globleHandler = std::set_new_handler(currentHandler);//设定X对应的handler并保存系统全局handler
    void *memory;
    try{
        memory = ::operator new[](size);//使用全局分配
    }
    catch(std::bad_alloc&){//分配失败
        std::set_new_handler(globleHandler);//恢复全局handler
        throw;
    }
    std::set_new_handler(globleHandler);//分配成功,恢复全局
    return memory;//将对应首地址返回
}

class Y{
private:
    int y;
    static new_handler currentHandler;//静态声明
public:
    static new_handler set_new_handler(new_handler handler);//重载set_new_handler
    void *operator new[](size_t size);//重载operator new[],可以分配数组
};
new_handler Y::currentHandler = 0;//默认定义并初始化为0
new_handler Y::set_new_handler(new_handler handler){//定义静态
    new_handler oldHandler = currentHandler;//保存当前Handler
    currentHandler = handler;//重新设定当前handler
    return oldHandler;//返回上一次使用的handler
}
void *Y::operator new[](size_t size){//定义静态
//当new的时候使用
    cout << "y test" << endl;
    new_handler globleHandler = std::set_new_handler(currentHandler);//设定X对应的handler并保存系统全局handler
    void *memory;
    try{
        memory = ::operator new[](size);//
    }
    catch(std::bad_alloc&){//分配失败
        std::set_new_handler(globleHandler);//恢复全局handler
        throw;
    }
    std::set_new_handler(globleHandler);//分配成功,恢复全局
    return memory;//将对应首地址返回
}

int main(void)
{
    X::set_new_handler(NoMoreMemoryX);//设定X对应的handler
    X *xBigData = new X[10];

    Y::set_new_handler(NoMoreMemoryY);//设定X对应的handler
    Y *yBigData = new Y[10000000000000];
    return 0;
}

这里写图片描述
X和Y类通过重载operator new[]来实现类别数组的分配。set_new_handler中设定设定currentHandler,并记录上一次handleroperator new[]中设定currentHandler,并在分配成功或者失败后恢复先前的handler。总体设计思路就是通过保存和恢复机制,利用全局的set_new_handler和operator new[]实现每个类对应的new-handler

3、设计NewHandleSupport类

从上面可以看出X和Y中关于new-handle的处理很类似,所以可以使用模板,使得代码重复率更加高。为什么将NewHandleSupport模板类?首先类全部是静态成员,假如不是模板,那么继承下来的静态成员也只有一份拷贝,导致X和Y不能有独自的currentHandler成员,所以可以通过定义模板类,使得每个X都有独自的currentHandler。这真是很聪明的机制啊。设计一个NewHandleSupport模板,并将X类继承NewHandleSupport<X>,那么就可以继承对应的功能。通过模板增加了代码的可重用性。设计模板仅仅是为了让每个子类都拥有对应的成员函数。

template <typename T>//定义模板
class NewHandlerSupport{
private:
    static new_handler currentHandler;//静态声明
public:
    static new_handler set_new_handler(new_handler handler);//重载set_new_handler
    static void *operator new[](size_t size);//重载operator new[],为了分配数组

};
template <typename T>
new_handler NewHandlerSupport<T>::currentHandler = 0;//默认定义并初始化为0

template <typename T>
new_handler NewHandlerSupport<T>::set_new_handler(new_handler handler){//定义静态
    new_handler oldHandler = currentHandler;//保存当前Handler
    currentHandler = handler;//重新设定当前handler
    return oldHandler;//返回上一次使用的handler
}
template <typename T>
void *NewHandlerSupport<T>::operator new[](size_t size){//定义静态
    cout << "x test" << endl;
    new_handler globleHandler = std::set_new_handler(currentHandler);//设定X对应的handler并保存系统全局handler
    void *memory;
    try{
        memory = ::operator new[](size);//使用全局分配
    }
    catch(std::bad_alloc&){//分配失败
        std::set_new_handler(globleHandler);//恢复全局handler
        throw;
    }
    std::set_new_handler(globleHandler);//分配成功,恢复全局
    return memory;//将对应首地址返回
}

class X:public NewHandlerSupport<X>{
public:
    int x;
};
class Y:public NewHandlerSupport<Y>{
public:
    int y;
};
int main(void)
{
    new_handler oldHandler;
    //set_new_handler(NoMoreMemory);//设定全局handler
    X::set_new_handler(NoMoreMemoryX);//设定X对应的handler
    X *xBigData = new X[10];

    Y::set_new_handler(NoMoreMemoryY);//设定X对应的handler
    Y *yBigData = new Y[10000000000000];

    int *pBigData = new int[10000000000000];

    return 0;
}

这里写图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有时需要偏执狂

请我喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值