转自:http://www.51testing.com/html/70/n-827070.html

在C++语言中,我们经常会使用new给一个对象分配内存空间,而当内存不够会出现内存不足的情况。C++提供了两中报告方式:

  1、抛出bad_alloc异常来报告分配失败;

  2、返回空指针,而不会抛出异常。

  C++为什么会采用这两种方式呢?这主要是由于各大编译器公司设计C++编译器公司的结果,因为标准C++是提供了异常机制的。例如,VC++6.0中当new分配内存失败时会返回空指针,而不会抛出异常。而gcc的编译器对于C++标准支持比较好,所以当new分配内存失败时会抛出异常。

  究竟为什么会出现这种情况呢?

  首先,C++是在C语言的基础之上发展而来,而且C++发明时是想尽可能的与C语言兼容。而C语言是一种没有异常机制的语言,所以C++应该会提供一种没有异常机制的new分配内存失败报告机制;(确实是如此,早期的C++还没有加入异常机制)

  其次在返回空指针的实现过程中,C++采用的是malloc/calloc 等分配内存的函数,该类函数不会抛出异常,但是在分配内存失败时会返回“空指针”。

  最后,对于标准的C++,有着比较完善的异常处理机制,所以对于出现异常时,会抛出响应的异常。对于new分配失败时,系统会抛出bad_alloc异常。

  鉴于以上原因,我们在不同的编译器需要new分配失败时做不同的处理。例如:

  情况1:

int* p = new int(5);
if ( p == 0 ) // 检查 p 是否空指针
    return -1;
...

  情况2:

try {
      int* p = new int(5);
        // 其它代码
} catch ( const bad_alloc& e ) {
      return -1;
}

  情况1和情况2的代码都是对于new失败时的处理,而针对不同的编译器,可以这种处理会完全失效。如果在gcc编译器采用情况1,那么if(p==0)完全是没有意义的,因为不管new内存分配成功失败与否,都不会出现p=0的情况。即,如果分配成功,p=0完全不可能;而分配失败,new会抛出异常跳过其后面的代码。而需要采用情况2的处理方式,即应该来捕捉异常。

  同样,如果在VC++6.0中采用情况2的代码,那么new分配失败时,完全不会抛出异常,那么捕捉异常也是徒劳的。

  所以在new分配内存的异常处理时要特别小心,可以两种方式联合使用,来解决跨平台跨编译器的难题。

  当然情况2中的异常处理代码是最简单的处理方式,下面我们为其制定一个客户制定的错误处理函数,即new-handler。

typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();

这里首先定义new-handler函数指针类型,然后定义一个new-handler函数set_new_handler,其参数是指向operator new无法分配足够内存时应该被调用的函数。其返回指也是一个指针,指向set_new_handler被调用前正在执行(但是马上就要被替换)的那个new-handler函数。下面设计一个当operator new无法分配足够内存时应该被调用的函数:

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

std::abort();
}

  使用noMemoryToAlloc函数的代码为:

int main()
{
       set_new_handler(nomorememory);
       int *pArray = new int[100000000000000L];

...

}

  当operator new无法分配足够空间时,noMemoryToAlloc就会被调用,于是程序就会发出一个错误信息cerr之后,调用abort函数结束程序。

  如果operator new无法分配足够空间时,我们希望不断调用new-handler函数,直到找到足够内存为止,那么我们的operator new函数就可以设计为:

void *operator new(std::size_t size) throw(std::bad_alloc)
{
        if ( size==0 ) {
             size  = 1;
        }
       while (true) {
            调用malloc等内存分配函数来尝试分配size大小的内存;
            if ( 分配成功 )
                 return 指向分配得来的内存指针;
            new_handler globalHandler  = set_new_handler(0);
            set_new_handle(globalHandler);
            if(globalHandler)
                   (*globalHandler)();
           else
                   throw std::bad_alloc();
       }
}

转自:http://blog.sina.com.cn/s/blog_9f1c09310101953s.html

使用new分配内存失败时往往会使用asert()终止程序,但是这只能在除错模式下abert函数才能有效,在生产模式下,abert只是一个void指令,所以连程序都跳不出来。

    而当new操作失败时,一个好的程序不能简单的终止程序就行了,而是要尝试去释放内存
    如何能在new操作失败,在抛出异常之前先把相应的处理做了呢?这就要用到new_handler了,它是在抛出exception调用的。为了指定这个所谓的“内存不足处理函数,new_handler”,client必须调用set_new_handler,这是头文件提供的函数,用法:
    typedef void (*new_handler)()
    new_handler set_new_handler(new_handler p) throw();
简单的程序测试:
#include "stdafx.h"
#include
#include
using namespace std;
 
void NoMoreMemory()
{
cout<<"Unable to statisty request for memory"<<endl;
abort();
}
 
int _tmain(int argc, _TCHAR* argv[])
{
set_new_handler(NoMoreMemory);
int *p=new int[536870911];
return 0;
}
注:当operator new 无法满足内存需求时,它会不只一次地调用new_handler函数(如果new_handler没有退出程序的话);它会不断地调用,直到找到足够的内存为止。因此一个良好设计的new_handler函数必须完成下列事情之一:
1)让更多的内存可用。这或许能够让operator new 的下一次内存配置行为成功。实现此策略的方法之一就是在程序起始时配置一大块内存,然后在new_handler第一次被调用时释放之。如此的释放动作常常伴随着某种警告信息,告诉用户目前的内存已经处于低水位,再来的内存需求可能失败,除非有更多的内存回复自由身。
2)安装一个不同的new_handler,如果目前的new_handler无法让更多的内存可用,或许它知道另一个new_handler手上我有比较多的资源。果真如此,目前的new_handler就可以安装另外一个new_handler以取代自己(只要再调用一次set_new_handler即可)。当operator new下次调用new_handler函数时,它会调用最新安装的那个。
3)卸除掉这个new_handler,也就是说,将null指针传给set_new_handler,一旦没有安装任何new_handler,operator new就会在内存配置失败时抛出一个类型为std::bad_alloc的exception。
4)抛出一个exception,类型为std::bad_alloc(或者派生类型)。这样的exception不会被operator new捕获,所以它们就会传动到最初踢出内存需求的那个点上
5)不返回,直接调用abort或exit
https://blog.csdn.net/gudongxian/article/details/48196499

处理new分配内存失败情况的更多相关文章

  1. C++内存管理5-处理new分配内存失败情况(转)

    C++内存管理5-处理new分配内存失败情况(转) endl; 参考博客: https://www.cnblogs.com/findumars/p/9905195.html

  2. C++new失败的处理(如果 new 分配内存失败,默认是抛出异常的,但也可以取消异常)

    我们都知道,使用 malloc/calloc 等分配内存的函数时,一定要检查其返回值是否为“空指针”(亦即检查分配内存的操作是否成功),这是良好的编程习惯,也是编写可靠程序所必需的.但是,如果你简单地 ...

  3. malloc函数分配内存失败的常见原因

    malloc()函数分配内存失败的常见原因:  1. 内存不足.  2. 在前面的程序中出现了内存的越界访问,导致malloc()分配函数所涉及的一些信息被破坏.下次再使用malloc()函数申请内存 ...

  4. 在内存充足时malloc函数分配内存失败的原因及解决

    昨天在修改自己的代码的时候,碰到了malloc函数内存分配失败,上网翻了翻,一个很可能的原因是之前的代码出现了越界操作,导致malloc分配函数所涉及的一些信息被破坏.在这个思想的指导下,今天又是郁闷 ...

  5. Unix系统编程()在堆上分配内存

    在堆上分配内存:malloc和free 一般情况下,C程序使用malloc函数族在堆上分配和释放内存.较之brk和sbrk,这些函数具备不少优点: 属于C语言标准的一部分 更易于在多线程程序中使用 接 ...

  6. 浅析C++内存分配与释放操作过程——三种方式可以分配内存new operator, operator new,placement new

    引言:C++中总共有三种方式可以分配内存,new operator, operator new,placement new. 一,new operator 这就是我们最常使用的 new 操作符.查看汇 ...

  7. du: fts_read 失败: 无法分配内存

    今天在查看一个大的文件时突然报出一个du: fts_read 失败: 无法分配内存的错误. 用 ulimit -a 查看下 core file size (blocks, -c) 0 data seg ...

  8. linux设备驱动归纳总结(五):1.在内核空间分配内存【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-79134.html linux设备驱动归纳总结(五):1.在内核空间分配内存 xxxxxxxxxxxx ...

  9. c语言中-----分配内存函数

    原型: void * realloc(void *p, size_t  size); realloc 可以对给定的指针所指的空间进行扩大 或者 缩小, 原有内存的数据保持不变.当然,对于缩小,则缩小部 ...

随机推荐

  1. (转)Eclipse在线配置Hibernate Tools

    http://blog.csdn.net/yerenyuan_pku/article/details/52733403 查看Eclipse版本 Eclipse针对程序开发有很多发行版本,除了开发语言的 ...

  2. jQuery鼠标划入划出

    今天来简单的谈谈jQuery的一个划入划出的方法,.首先划入划出能想到的东西有哪些呢,. 1:hover 2:mouseenter/mouseleave 3:mouseover/mouseout. 一 ...

  3. Spring Boot 与消息

    一.消息概述 在大多数应用中,可以通过消息服务中间件来提升系统的异步通信.扩展解耦和流量削峰等能力. 当消息发送者发送消息后,将由消息代理接管,消息代理保证消息传递到指定目的地. 消息队列主要有两种形 ...

  4. Django 缓存之配置Redis

    一.cache介绍 由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存. 缓存工作原理:缓存是将一些常用的数据保存内存或 ...

  5. vue-cli项目结构分析

    总体框架 一个vue-cli的项目结构如下,其中src文件夹是需要掌握的,所以本文也重点讲解其中的文件,至于其他相关文件,了解一下即可. 文件结构细分 1.build——[webpack配置] bui ...

  6. python学习,使用requests库来模拟登录github,post请求。

    这次我们要模拟登录的页面是 https://github.com/login 首先我们先尝试着登陆一遍分析一下请求, 打开开发者工具下的network选项, 可以很清楚的看到这个会话session,而 ...

  7. Journals in Fluid Mechanics

    journal of fluid mechanics physics of fluids annual review of fluid mechanics

  8. selectByExampleWithBLOBs-----搜索结果包含大字段类型----搜索结果包含大字段类型

    http://www.jb51.net/article/121482.htm mybatis generator 使用方法教程(生成带注释的实体类)

  9. COJ 1156 Switching bulbs

    一道模拟题目 对于所有0 还是 1 我们都可以想象做均为 0 的状态 v[i]表示原来的值 但是对于原来为1的要加上其所在的值作为初始值 然后转化后 a[i] = -v[i]  , 如果原来为0 , ...

  10. poj 1364 查分约束

    #include<stdio.h> #include<iostream> #include<stack> #include<string.h> usin ...