注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

(转载)C++小知识57—处理NEW分配失败  

2014-10-19 13:54:44|  分类: C++(VC)编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

今天在看“C++小知识5:内存使用优秀习惯”(http://fpcfjf.blog.163.com/blog/static/554697932009913101553144/)这篇博客时,发现还是有一些细节没有说清楚,本着不断的否定之否定的原则,转载了别人的文章,以咨为记。

处理new分配失败

分类: c++ 2011-11-21 21:07 1287人阅读 评论(0) 收藏 举报

exceptionobjectclass编译器cnull

1993年前,c++一直要求在内存分配失败时operator new要返回0,现在则是要求operator new抛出std::bad_alloc异常。很多c++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator new(以及operator new[])以继续提供返回0功能。这些形式被称为“无抛出”,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象:

 

[cpp] view plaincopy

class widget { ... }; 

 

widget* pw1 = new widget;// if allocated failed throw std::bad_alloc 

 

if (pw1 == 0) ...   // must be failed 

 

widget* pw2 = new (nothrow)widget;  // if allocated failed return 0(NULL) 

     

if (pw2 == 0) ...   // maybe successful  

operator new默认情况下如果不能满足内存分配请求时会抛出的异常类型std::bad_alloc。因此,如果你不愿意看到诸如:widget* pw2 = new (nothrow) widget; 这样带着nothrowoperator new,最简单的方法是使用set_new_handler自定义newhandler函数。最简单的例子如下:

 

[cpp] view plaincopy

// main.cpp (vc9.0) 

 

#include "stdafx.h" 

#include<new> 

#include<iostream> 

#include<stdlib.h> 

using namespace std; 

 

void __cdecl newhandlerfunc() 

    cerr << "Allocate failed." << endl; 

    abort(); 

 

int main()  

    set_new_handler (newhandlerfunc); 

    while (1)  

    { 

        int* p = new int[500000000];    // based on own machine's memory size 

        cout << "Allocating 500000000 int." << endl; 

    } 

newhandlerfunc函数中没有参数也没有返回值,可提供的信息有限,这样的全局通用函数在c++项目中所能起的作用不大。所以,鉴于c++本身的面向对象的设计,我们考虑每个类有自己的newhandler,与全局的newhandler共存。比较简单的例子如下:

 

[cpp] view plaincopy

// main.cpp (vc9.0) 

 

#include "stdafx.h" 

#include<new> 

#include<iostream> 

#include<stdlib.h> 

using namespace std; 

 

void __cdecl newhandlerfunc() 

    cerr << "Allocate failed." << endl; 

    abort(); 

 

void __cdecl xnewhandlerfunc() 

    cerr << "Allocate x object failed" << endl; 

    abort(); 

 

class x { 

public: 

    x() 

    { 

        while (1)  

        { 

            int* p = new int[500000000]; 

            cout << "Allocating 500000000 int." << endl; 

        } 

    } 

 

    static new_handler set_new_handler(new_handler p) 

    { 

        new_handler oldhandler = currenthandler; 

        currenthandler = p; 

        return oldhandler; 

    } 

 

    static void * operator new(size_t size) 

    { 

        // setup x's new_handler, now it replaces global handler 

        new_handler globalhandler = set_new_handler(currenthandler);  

 

        void *memory; 

        try  

        {    

            memory = ::operator new(size); // try to allocate memory 

        } 

        catch (std::bad_alloc&) // handled by x's new_handler 

        {    

            set_new_handler(globalhandler); // recover old new_handler      

            throw;  // rethrow exception 

        } 

 

        // allocate normally 

        std::set_new_handler(globalhandler);    // recover old new_handler  

        return memory; 

    } 

 

private: 

    static new_handler currenthandler; 

}; 

 

new_handler x::currenthandler = NULL; 

 

int main()  

    //set_new_handler(newhandlerfunc); 

    //while (1)  

    //{ 

    //  int* p = new int[500000000]; 

    //  cout << "Allocating 500000000 int." << endl; 

    //} 

    x::set_new_handler(xnewhandlerfunc); 

    x* p = new x; 

 

    return 0; 

如果每个类都这样地写一遍,感觉有些代码重复,所以可能想到会写一个基类,让所有的子类可以继承set_new_handleroperator new功能,但要使每个子类有不同的currenthandler数据成员,一个比较简单的方法就是设计一个模板。

例子如下:

 

[cpp] view plaincopy

// SetNewHandler.h (vc9.0) 

 

#include<new> 

#include<iostream> 

#include<stdlib.h> 

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); 

 

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) 

    new_handler globalhandler = set_new_handler(currenthandler); 

    void *memory; 

    try  

    { 

        memory = ::operator new(size); 

    } 

    catch (std::bad_alloc&)  

    { 

        set_new_handler(globalhandler); 

        throw; 

    } 

 

    std::set_new_handler(globalhandler); 

    return memory; 

 

template<class t> 

new_handler newhandlersupport<t>::currenthandler = NULL; 

 

 

[cpp] view plaincopy

// main.cpp (vc9.0) 

 

#include "stdafx.h" 

#include "SetNewHandler.h" 

#include<new> 

#include<iostream> 

#include<stdlib.h> 

using namespace std; 

 

void __cdecl newhandlerfunc() 

    cerr << "Allocate failed." << endl; 

    abort(); 

 

void __cdecl xnewhandlerfunc() 

    cerr << "Allocate x object failed" << endl; 

    abort(); 

 

void __cdecl ynewhandlerfunc() 

    cerr << "Allocate y object failed" << endl; 

    abort(); 

 

class x { 

public: 

    x() 

    { 

        while (1)  

        { 

            int* p = new int[500000000]; 

            cout << "Allocating 500000000 int." << endl; 

        } 

    } 

 

    static new_handler set_new_handler(new_handler p) 

    { 

        new_handler oldhandler = currenthandler; 

        currenthandler = p; 

        return oldhandler; 

    } 

 

    static void * operator new(size_t size) 

    { 

        // setup x's new_handler, now it replaces global handler 

        new_handler globalhandler = set_new_handler(currenthandler); 

 

        void *memory; 

        try  

        {    

            memory = ::operator new(size); // try to allocate memory 

        } 

        catch (std::bad_alloc&) // handled by x's new_handler 

        {    

            set_new_handler(globalhandler); // recover old new_handler      

            throw;  // rethrow exception 

        } 

 

        // allocate normally 

        std::set_new_handler(globalhandler);    // recover old new_handler  

        return memory; 

    } 

 

private: 

    static new_handler currenthandler; 

}; 

 

new_handler x::currenthandler = NULL; 

 

class y: public newhandlersupport<y>  

public: 

    y() 

    { 

        while (1)  

        { 

            int* p = new int[500000000]; 

            cout << "Allocating 500000000 int." << endl; 

        } 

    } 

};       

 

int main()  

    //set_new_handler(newhandlerfunc); 

    //while (1)  

    //{ 

    //  int* p = new int[500000000]; 

    //  cout << "Allocating 500000000 int." << endl; 

    //} 

 

    //x::set_new_handler(xnewhandlerfunc); 

    //x* p = new x; 

 

    y::set_new_handler(ynewhandlerfunc); 

    y* p = new y; 

 

    return 0; 

参考:<<Effective C++>>

 

转载请注明。

  评论这张
 
阅读(448)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017