以下的一段代码是不是很眼熟

     char *a = new char[1024];
     if(a == NULL) {
           //申请失败,处理
     }
     else {
          //正常处理....
     }

的确经常会在程序里这样用,特别是上学时候很多的教科书里想当然的申请失败,返回了NULL。由于使用C++的同学一般不太使用Exception机制,而会忽略异常。其实C++的库中对operator new的声明如下形式。

void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw();
void* operator new (std::size_t size, void* ptr) throw();

第一种是我们最常使用的,这种方式在申请失败时会抛出std::bad_alloc的异常,而非返回NULL,如下代码。

#include <iostream>
#include <unistd.h>
using namespace std;

int main(void)
{
    while(1) {
        char *a = new char[1024*1024*1024];
        if( a != NULL) {
            cout<<"new 1GB buffer size"<<endl;
        }
        else {
            cout<<"new failed!\n"<<endl;
            return -1;
        }
    }
    return 0;
}

其运行结果如下图,可以看出,程序抛出了std::bad_alloc的异常

第二种则添加了nothrow参数,使得new不抛出异常。
对上面的第8行做如下修改:

        char *a = new(nothrow) char[1024*1024*1024];

从运行结果就可以看出来,程序不抛出异常,而直接返回NULL指针了。

最后一种是placement new,即是在ptr指向的空间上new对象,本身并不申请空间,因此也不会异常。

默认情况下的new是会抛出std::bad_alloc异常的,可以使用set_new_handler来处理默认情况下的异常,代码如下:

#include <iostream>
#include <unistd.h>
using namespace std;

void no_memory () {
  cout << "Failed to allocate memory!"<<endl;
  //这里可以写点清理代码
  throw bad_alloc();  //默认处理函数,继续往上层抛出
  exit (1);
}

int main(void)
{
    set_new_handler(no_momery);
    while(1) {
        char *a = new char[1024*1024*1024];
        if( a != NULL) {
            cout<<"new 1GB buffer size"<<endl;
        }
        else {
            cout<<"new failed!\n"<<endl;
            return -1;
        }
    }
    return 0;
}

则程序执行到new抛出了异常时,会利用set_new_handler的函数进行处理,也可以不throw转而直接exit/return等,执行效果如下:

这段代码告诫自己平常学习应该多钻研,多问,不能想当然,特别是学校课堂上的东西都太过于理想。如果不清楚的应该多看官方一点的东西,有关operator new的东西可以查看这里,描述的很清楚。