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

今天主要总结关于使用 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. Matlab流体后处理中的奇淫巧术总结

    Matlab流体后处理中的奇淫巧术总结 主要参考\demos\volvec.m示例 1.等值面绘制 %% Isosurface of MRI Data cla load mri D = squeeze ...

  2. 【Linux】tmux安装(非root)及其使用

    tmux(terminal multiplexer)是Linux上的终端复用神器. 1. 安装 (1)下载 下载及其依赖软件. wget -c https://github.com/tmux/tmux ...

  3. R语言因子排序

    画图的时候,排序是个很重要的技巧,比如有时候会看下基因组每条染色体上的SNP的标记数量,这个时候直接做条形图是一种比较直观的方法,下面我们结合实际例子来看下: 在R环境下之际构建一个数据框,一列染色体 ...

  4. EXCEL-批量删除筛选出的行,并且保留首行

    筛选->ctrl+G->可见单元格->鼠标右键->删除整行. 之前的时候,是有个方法类似于上述步骤,可以保留标题行的,但是,不知道是不是少了哪一步,上述过程总是会删除标题行.就 ...

  5. RocketMQ这样做,压测后性能提高30%

    从官方这边获悉,RocketMQ在4.9.1版本中对消息发送进行了大量的优化,性能提升十分显著,接下来请跟着我一起来欣赏大神们的杰作. 根据RocketMQ4.9.1的更新日志,我们从中提取到关于消息 ...

  6. 位运算符在JS中的妙用

    正文 位运算 JavaScript 中最臭名昭著的 Bug 就是 0.1 + 0.2 !== 0.3,因为精度的问题,导致所有的浮点运算都是不安全的,具体原因可详见<0.1 + 0.2不等于0. ...

  7. C语言产生随机数(伪)

    C语言的获取随机数的函数为rand(), 可以获得一个非负整数的随机数.要调用rand需要引用头文件stdlib.h.要让随机数限定在一个范围,可以采用模除加加法的方式.要产生随机数r, 其范围为 m ...

  8. final&static

    final 1.final修饰类,那么该类不能有子类,那么也就没有子类重写父类的方法,也就没有多态 2.final修饰成员变量,那么成员变量要么显式赋值(用第一种),要么在构造方法中赋值 无论哪一种, ...

  9. 使用OPC与PLC通讯 一

    总结自己在opc与自控开发的经验.首先介绍OPC DA模式下的OPC各种操作. 在使用opc时需要引用到 OPCDAAuto.dll 这个类库. 在项目引用后需要注册这个类库,否则程序跑起来会报错,& ...

  10. Grafana 任意文件读取漏洞 (CVE-2021-43798)学习

    漏洞概述 Grafana是一个跨平台.开源的数据可视化网络应用程序平台.用户配置连接的数据源之后,Grafana可以在网络浏览器里显示数据图表和警告. Grafana 的读取文件接口存在未授权,且未对 ...