C++中的new

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

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

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 这一行的,而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 这一行同样是编译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排错。
原文链接: https://www.cnblogs.com/lanyuliuyun/archive/2013/04/25/3041476.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/85873

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午10:17
下一篇 2023年2月9日 下午10:17

相关推荐