自己之前纠正过这个问题,但还是忘了。今天再拿出来。

今天主要总结关于使用 c++ 标准中的 new 关键字。

【结论】

  A、处理new可能抛出的异常

  B、针对new使用std::nothrow不抛出异常

1、错误示范

  下面一段代码,使用new向堆申请空间,再释放的过程

 1   char *pbuf = NULL;
2 // 这里有bug, 后面讲
3 pbuf = new char[128];
4
5 if ( NULL == pbuf)
6 {
7 std::cout << "\n error, pbuf created failure\n";
8 }
9
10 // 2、doing sth
11
12 // 3、release
13 delete pbuf;
14 pbuf = NULL;

  A、代码中 第 3 行 有错误, 准确的说是 这样写不够规范。为什么?

  B、因为:    第3行代码 结果有两种:  

    1)、申请空间成功,并且返回申请成功的地址

    2)、 申请失败,则抛出异常: std::bad_alloc 重点),而不是返回 NULL 或者 nullptr. 当然, 上面第4行代码也不会执行。

  C、那,怎么改?

  

2、正确做法

  上面分析到了,是因为使用不规范引起的。下面就是规范的写法。修改方法有 2 种。

  A、使用 std::nothrow

 1     char *pbuf = NULL;
2 // 这里有bug, 后面讲
3 pbuf = new(std::nothrow) char[128];
4
5 if ( NULL == pbuf)
6 {
7 std::cout << "\n error, pbuf created failure\n";
8 }
9
10 // 2、doing sth
11
12 // 3、release
13 delete pbuf;
14 pbuf = NULL;

  对比上面错误的做法, 变化就在 第3行。   这样就可以了: 申请空间失败, 就会返回 NULL, 当前也会继续执行 第3行以后的代码。

  B 、既然 new 可能会抛出异常std::badalloc,那么,我们就需要处理异常。

 1     char *pbuf = NULL;
2 try
3 {
4 // 1、需要处理可能抛出的异常
5 pbuf = new char[128];
6 }
7 catch (const std::bad_alloc& error)
8 {
9 std::cout << "\nerror: " << error.what() << endl;
10 return;
11 }
12
13 // 2、doing sth
14
15 // 3、release
16 delete pbuf;
17 pbuf = NULL;

  对比上面的错误示范,变化:

    1)、增加了对 new 发出异常的捕获。

    2)、去掉了对指针为NULL的判断。

  这里的代码, new 失败后, 将不会返回NULL, 而是抛出异常。 需要对异常处理。显然: 判断 if (NULL == pbuf) 就完全失去意义了。

    所以,判断new是否返回成功,则需要添加对异常的处理。

3、为什么?

  (以下均为个人观点)市面上的编译器 可谓雨后春笋。 new 和 delete 族当然不一样。 但总体原则:

  A、 new(std::nothrow) 的方式是沿袭了C的习惯。

  B、new 抛出异常的形式 则是 标准呢c++的形式。  

  C、为什么有这样两种的形式?   直接使用 c++标准的的形式不好吗? 但是需要考虑兼容,C语言中, 判断指针为NULl习惯是个好习惯,可以继续沿袭。而new抛出异常的c++标准方式是对 C的扩展。

  D、这样做,既是对C的编程习惯的延续,又扩展了c++关于new定义,满足c++的标准形式。双赢。

4、std::badalloc

  这个是? 别急, 定义如下:

 1 class bad_alloc
2 : public exception
3 {
4 public:
5
6 bad_alloc() throw()
7 : exception("bad allocation", 1)
8 {
9 }
10
11 private:
12
13 friend class bad_array_new_length;
14
15 bad_alloc(char const* const _Message) throw()
16 : exception(_Message, 1)
17 {
18 }
19 };

  其实也是继承的 std::exception 。 这里出现了友元类: bad_array_new_length, 我们再看看他的定义

 1 class bad_array_new_length
2 : public bad_alloc
3 {
4 public:
5
6 bad_array_new_length() throw()
7 : bad_alloc("bad array new length")
8 {
9 }
10 };

  原来是这样。

5、new/delete 定义

  下面是来自VS2015 up3中的new和delete的源码 vcruntime_new.h: 下面的代码 已经掐头去尾

 1     namespace std
2 {
3 struct nothrow_t { };
4
5 extern nothrow_t const nothrow;
6 }
7 #endif
8
9 _Ret_notnull_ _Post_writable_byte_size_(_Size)
10 _VCRT_ALLOCATOR void* __CRTDECL operator new(
11 size_t _Size
12 );
13
14 _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size)
15 _VCRT_ALLOCATOR void* __CRTDECL operator new(
16 size_t _Size,
17 std::nothrow_t const&
18 ) throw();
19
20 _Ret_notnull_ _Post_writable_byte_size_(_Size)
21 _VCRT_ALLOCATOR void* __CRTDECL operator new[](
22 size_t _Size
23 );
24
25 _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size)
26 _VCRT_ALLOCATOR void* __CRTDECL operator new[](
27 size_t _Size,
28 std::nothrow_t const&
29 ) throw();
30
31 void __CRTDECL operator delete(
32 void* _Block
33 ) throw();
34
35 void __CRTDECL operator delete(
36 void* _Block,
37 std::nothrow_t const&
38 ) throw();
39
40 void __CRTDECL operator delete[](
41 void* _Block
42 ) throw();
43
44 void __CRTDECL operator delete[](
45 void* _Block,
46 std::nothrow_t const&
47 ) throw();
48
49 void __CRTDECL operator delete(
50 void* _Block,
51 size_t _Size
52 ) throw();
53
54 void __CRTDECL operator delete[](
55 void* _Block,
56 size_t _Size
57 ) throw();
58
59 #ifndef __PLACEMENT_NEW_INLINE
60 #define __PLACEMENT_NEW_INLINE
61 _Ret_notnull_ _Post_writable_byte_size_(_Size)
62 inline void* __CRTDECL operator new(size_t _Size, _Writable_bytes_(_Size) void* _Where) throw()
63 {
64 (void)_Size;
65 return _Where;
66 }
67
68 inline void __CRTDECL operator delete(void*, void*) throw()
69 {
70 return;
71 }
72 #endif
73
74 #ifndef __PLACEMENT_VEC_NEW_INLINE
75 #define __PLACEMENT_VEC_NEW_INLINE
76 _Ret_notnull_ _Post_writable_byte_size_(_Size)
77 inline void* __CRTDECL operator new[](size_t _Size, _Writable_bytes_(_Size) void* _Where) throw()
78 {
79 (void)_Size;
80 return _Where;
81 }
82
83 inline void __CRTDECL operator delete[](void*, void*) throw()
84 {
85 }
86 #endif

  可以看到 , 上面的代码中 可以看到 声明中存在不会抛出异常的定义,大胆推测,可能是为了延续C的判断指针是否为NULL的扩展。

c++关于使用new的纠正的更多相关文章

  1. C#图片色彩的纠正-上

    WPF(C#)图片色彩的纠正-上 WPF(C#)图片色彩的纠正-下 前言 对图片进行色彩的纠正,其实与WPF是没有什么关系的,为什么标题又是“WPF(C#)图片色彩的纠正”呢,因为这些图片色彩的纠正功 ...

  2. 对属性NaN的理解纠正和对Number.isNaN() 、isNaN()方法的辨析

    1.属性NaN的误解纠正 NaN (Not a Number)在w3c 中定义的是非数字的特殊值 ,它的对象是Number ,所以并不是任何非数字类型的值都会等于NaN,只有在算术运算或数据类型转换出 ...

  3. CSS下拉列表错误纠正

    上一篇关于CSS制作下来列表的错误纠正. 在上一篇中,用CSS只做了下拉列表,但是鼠标不放在导航栏上的时候,下拉列表也是出来的.具体错误就是 div ul{ list-style:none; max- ...

  4. C# winform 若要在加载设计器前避免可能发生的数据丢失,必须纠正以下错误

    winform中有时添加了新控件之后编译会报错: 若要在加载设计器前避免可能发生的数据丢失,必须纠正以下错误,如图: 解决方案: 1.“解决方案”→“批生成”→“清理”→“确定”: 2.“解决方案”→ ...

  5. JAVA classpath, 纠正我一直以来错误的认知

    如何调在CLI中使用java tool(JDK中的java命令)调用一个打包在jar中的类,我想大多数人都能给出笼统的方案: java -classpath xxxxx com.test.classA ...

  6. VS2008 由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题。

    提示这个错误,自己的程序是在VS2008下编译的C/C++ win32程序,自己当时在win7上开发测试,都没有问题,正常使用,也在另一台xp系统上也试了,都没有问题.就发给客户了,没想到有些客户竟然 ...

  7. 关闭 Mac 拼写自动纠正与横线转换

    如果你是个程序员, 如果你恰好用 mac 自带的 notes 来做笔记, 很大可能性, 你会在里面贴代码, 但是, Mac 的拼写检查和自动纠正功能,会把代码变成你不想要的样子, 比如, 它会为你首字 ...

  8. 命令纠正工具 thefuck 的简单使用

    在unix系列的系统中,总会出现 命令拼写或者执行错误的情况, 比如 把 python 写成了pythou, cd 到一个不存在的目录,执行任务的权限 不够的问题, 这是心里 总是 在 fuck,但是 ...

  9. java 英文单词拼写纠正框架(Word Checker)

    Word Checker 本项目用于单词拼写检查. 项目简介 word checker 用于单词拼写检查. Github 地址 特性说明 支持 i18n 错误提示支持 i18N 支持英文的单词纠错 可 ...

  10. Noisy Channel模型纠正单词拼写错误

    本文介绍 Stanford<From Languages to Information>课程中讲到的 单词拼写错误 纠正.背后的数学原理主要是贝叶斯公式.单词拼写错误纠正主要涉及到两个模型 ...

随机推荐

  1. 手写Bitset优化

    一种优化方法,具体例子可以看这里 这里只是存一下手写Bitset的板子 struct Bitset { unsigned a[1600]; void reset() { memset(a,0,size ...

  2. Session和Cookie的原理,以及在分布式应用中出现的问题和解决方案

    产生原因 由于http协议是无状态的,同一个浏览器对服务器的两次请求之间是没有关系的,服务器认为两次请求都是全新的请求,不会记住上次请求成功的数据.然而现有的业务常常需要服务器能记住用户的访问情况, ...

  3. confluence——实现

    基于CentOS6.9 [root@localhost ~]# yum install mysql mysql-server -y [root@localhost ~]#yum install -y ...

  4. Macbook pro进入恢复模式以及无法进入恢复模式解决方案

    看网上很多说用Command+R进入恢复模式,但是,大部分都反馈说,此命令并不能进入恢复模式.我自己也尝试发现了同样问题,最终发现解决方案: 问题出在,[是重新启动电脑,而不是关机+按开机键,否则会造 ...

  5. 自动添加shell脚本头部信息

    autocmd BufNewFile *.sh exec ":call AddTitleForShell()" function AddTitleForShell() call a ...

  6. 漏洞分析:CVE-2017-17215

    漏洞分析:CVE-2017-17215 华为HG532路由器的命令注入漏洞,存在于UPnP模块中. 漏洞分析 什么是UPnP? 搭建好环境(使用IoT-vulhub的docker环境),启动环境,查看 ...

  7. javaSE高级篇5 — java8新特性详解———更新完毕

    java8新特性 在前面已经见过一些东西了,但是:挖得有坑儿 1.lambda表达式 lambda表达式是jdk1.8引入的全新语法特性 它支持的是:只有单个抽象方法的函数式接口.什么意思? 就是说: ...

  8. 学习Java的第十八天

    一.今日收获 1.java完全学习手册第三章算法的3.1比较值 2.看哔哩哔哩上的教学视频 二.今日问题 1.在第一个最大值程序运行时经常报错. 2.哔哩哔哩教学视频的一些术语不太理解,还需要了解 三 ...

  9. C++类的定义,成员函数的定义,对象的创建与使用

    类是一个模板,可用类生成一系列可用的实例.例如 int B就是生成了一个符合int的数据B,类也是一样,使用类名就可以直接生成一个实例, 该实例中包含类中所有的数据类型和对这些数据的操作方法. 首先, ...

  10. Linux下删除的文件如何恢复

    Linux下删除的文件如何恢复 参考自: [1]linux下误操作删除文件如何恢复 [2]Linux实现删除撤回的方法 以/home/test.txt为例 1.df -T 文件夹 找到当前文件所在磁盘 ...