C++中的new

C++中除了沿用C的alloc系列函数之外,还可以用new/new []来分配内存(这句是废话),我们在使用new这个operator的时候多是直接使用,而没有额外引用头文件。

写C语言代码写习惯的人都会在alloc函数之后,对指针做NULL判断,以检查内存分配是否成功,那么在C++中是否也需要以同样的方式来检查内存分配是否成功呢?根据实际code验证结果,答案是new成功返回即表示内存分配成功,不需检查指针是否为NULL,但是仍然会出现内存分配失败的情况,此时需要捕捉bad_alloc这种exceptin来知晓内存分配失败,bad_alloc是在new这个C++头文件(#include <new>)中声明的。废话先说到这里,下面以两段代码来作说明

 1 #include <iostream>

 2 #include <new>

 3 #include <cstdlib>

 4 

 5 using namespace std;

 6 

 7 int main(int argc, char *arg[])

 8 {

 9     char *buffer = NULL;

10 

11     try

12     {

13         buffer = new char[90000000000ul];      // 故意分配很大的一块内存,导致操作失败

14 

15         cout<<"The buffer address is: "<<static_cast<void*>(buffer)<<endl;

16     }

17     catch (const bad_alloc &ex)

18     {

19         cout<<"exception: "<<ex.what()<<endl;

20     }

21     catch (...)

22     {

23         cout<<"unknown exception"<<endl;

24     }

25     

26     if (NULL != buffer)

27     {

28         delete[] buffer;

29     }

30 

31     return 0;

32 }

对上面的代码进行编译和运行,结果如下

Administrator@attention /e/Code

$ g++ stl_new.cpp -lstdc++ -o stl_new.exe



Administrator@attention /e/Code

$ ./stl_new.exe

exception: std::bad_alloc



Administrator@attention /e/Code

$

可以看出分配失败时,的确throw出了bad_alloc,代码catch到这个exception即可知道内存分配失败。细心看上面的代码是有#include <new>这一行的,而C++的new头文件对new这个operator声明如下

void* operator new(std::size_t) throw (std::bad_alloc);

void* operator new[](std::size_t) throw (std::bad_alloc);

void operator delete(void*) throw();

void operator delete[](void*) throw();

void* operator new(std::size_t, const std::nothrow_t&) throw();

void* operator new[](std::size_t, const std::nothrow_t&) throw();

void operator delete(void*, const std::nothrow_t&) throw();

void operator delete[](void*, const std::nothrow_t&) throw();

其中很明显new和new[]这两个operator都被声明会throw出std::bad_alloc(入参只有size的那种,后面均指这种,不重复说明),那是不是因为引用new头文件的缘故而使用了这个特定类型的new了呢?

经过实际代码验证,答案为“不是”,实际上代码里去掉#include <new>这一行同样是编译OK的,且运行结果也一样。由此结论如下:

new这个operator是C++语言内置的,其本身在内存分配失败会throw出一个bad_alloc,因此我们在使用new进行内存/对象分配时,就必须使用catch来捕捉这种可能的bad_alloc来检查分配是否失败;若不做如此处理,被throw出来的bad_alloc会未在这一层被捕捉而一直向上冒泡,若我们的代码中一直不进行catch,则会一直冒泡到CRT,而CRT对这些未被捕捉异常,处理方式是调用abort()来直接结束整个程序,最终的后果便是程序异常退出。这里再罗嗦的贴一段代码来说明这一点

 1 #include <stdio.h>

 2 

 3 int main(int argc, char *argv[])

 4 {

 5     char *buffer = NULL;

 6     

 7     buffer = new char[90000000000ul];      // 故意分配很大的一块内存

 8     printf("The buffer address is: %p\n", buffer);

 9 

10     if (NULL != buffer)

11     {

12         delete[] buffer;

13     }

14 

15     return 0;

16 }

最终编译和运行结果为

Administrator@attention /e/Code

$ ./new.exe

terminate called after throwing an instance of 'std::bad_alloc'

  what():  std::bad_alloc



This application has requested the Runtime to terminate it in an unusual way.

Please contact the application's support team for more information.

 对此自己的感受便是,在C++代码中使用new,应该将其包括在try{}catch(){}中,以知道分配是否成功和避免未捕捉的异常而导致程序异常退出。

但实际实际上在非嵌入式的环境中,比如桌面环境,内存都比较充裕(加上操作系统虚拟内存机制),内存分配失败几乎是微乎其微,而导致很多的try{}catch(){}形同虚设,而使代码有些dirty。并且倘若真的是出现内存分配失败的问题,那多是意味着软已经出现了严重的错误(比如内存泄漏),就算在这里catch到本次分配失败,也对于整个系统恢复也没什么作用,因此很多代码里都是直接使用new,而没有将其包括在try{}catch(){}之中。

对此个人感觉是还是严谨的使用try{}catch(){}为好,毕竟内存分配失败了,也算是一种错误,应该即可就对此进行捕捉处理,将错误影响范围尽可能限制在出错的位置,这样避免错误扩大,也方便debug排错。

你可能感兴趣的:(C++)