《 高质量C++编程指南 》学习重点五
2011-05-06 10:29
295 查看
7.4如果函数的参数是一个指针,不要指望用该指针去申请动态内存。示例 7-4-1 中, Test 函 数的语句GetMemory(str, 200) 并没有使str 获 得期望的内存,str 依旧是NULL ,为什 么?
7-4-1 试图用指针参数申请动态内存 毛病出在函数GetMemory 中。编译器总是要为函数的每个参数制作临时副本,指针参数p 的副本是 _p ,编译器使 _p = p 。 如 果函数体内的程序修改了_p 的内容,就导致参数p 的 内容作相应的修改。这就是指针可以用作输出参数的原因。 在本例中,_p 申请了新的内存,只是把_p 所 指的内存地址改变了(_p指向所申请的内存),但是p 丝毫未变。所以函数GetMemory 并不能输出任何东西。 事实上,每执行一次GetMemory 就会泄露一块内存,因为没有用free 释放内存。 如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”, 见示例 7-4-2 。
7-4-2 用指向指针的指针申请动态内存 由于 “指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。 这种方法更加简单,见示例 7-4-3 。
7-4-3 用函数返回值来传递动态内存 用函数返回值来传递动态内存这种方法虽然好用,但是常常 有人把 return 语 句用错了。这里强调不要用 return 语句返回指向“栈内 存”的指针,因为该内存在函数结束时自动消亡, 见示例 7-4-4 。
7-4-4 return 语句返回指向“栈内存”的指针 用调试器逐步跟踪Test4 ,发现执行str = GetString 语 句后str 不再是NULL 指针,但是str 的内容不是 “ hello world ” 而是垃圾。 如果把 示例 7-4-4 改写成 示例 7-4-5 ,会怎么样?
7-4-5 return 语句返回常量字符串 函数Test5 运行虽然不会出错,但 是函数GetString2 的设计概念却是错误的。 因为GetString2 内的“hello world ”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2 ,它返回的始终是同一个“只读”的内存块。 小结: 若用指针参数去申请内存,有两种办法: 1. 用 “指向指针的指针”作为函数参数。 如示 例 7-4-2 2.用函数返回值来传递动态内存 。如示例 7-4-3 7.5 free 和 delete 把指针怎么啦? 别看 free 和 delete 的名字恶狠狠的(尤其是 delete ),它们只是把指针 所指的内存给释放掉,但并没有把指针本身干掉。 用调试器跟踪示例 7-5 ,发现指针 p 被 free 以后其地址仍然不变(非 NULL ),只是该地址对应的内存是垃圾, p 成了“野指针”。如果此时不把 p 设置为 NULL ,会让人误以为 p 是个合法的指针。 如果程序比较长,我们有时记不住 p 所指的内存是否已经被释放,在继续使用 p 之前,通常会用语句 if (p != NULL) 进行防错处 理。很遗憾,此时 if 语句起不到防错作用,因为即便 p 不是 NULL 指针,它也不指向合法的内存块。
7-5 p 成为野指针 7.6函数体内的局部变量在函数结束时 自动消亡。很多人误以为示例7-6 是正确的。理由是 p 是局部的指针变量,它消亡的时候会让它所指的动态内存一起完蛋。这是错觉!
7-6 试图让动态内存自动释放 我们发现指针有一些“似是而非”的特征: ( 1)指 针消亡了,并不表示它所指的内存会被自动释放。 (2 )内存被释放了,并不表示指针会消亡或者成了NULL指针。 这表明释放内存并不是一件可以草 率对待的事。也许有人不服气,一定要找出可以草率行事的理由: 如果程序终止了运行,一切指针都会消亡,动态内存会被操作系统回收。既然如此,在程序 临终前,就可以不必释放内存、不必将指针设置为NULL 了。终于可以偷懒而不会发生错误了吧? 想得美。如果别人把那段程序取出来用到其它地方怎么办? 小结: 函数体内的局 部变量在函数结束时自动消亡,因局部变量和参数都在栈内存。但如示例 7-6,虽然p是局部的指针变量,但其申请的是堆内存,并不会随着函数执行结束而消亡,导致内存泄漏。 7.7“野指针”不是NULL 指针,是指向“垃圾”内存的指针。人 们一般不会错用 NULL 指针,因为用 if 语句很容易判断。但是“野指针”是很危险的, if 语句对它不起作用。 “野指针”的成因主要有两种: ( 1 )指针变量没有被初始化。 任 何指针变量刚被创建时不会自动成为 NULL 指针,它的缺省值是随机的,它会乱 指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为 NULL ,要么让它指向合法 的内存。 例如 char *p = NULL; char *str = (char *) malloc(100); ( 2 )指针 p 被 free 或者 delete 之后,没有置为 NULL ,让人误以为 p 是个合法的指针。 参见 7.5 节。 ( 3 )指针操作超越了变量的作用范围。这种情况让人防不胜防, 示例程序如下: class A { public: void Func(void){ cout << “ Func of class A ” << endl; } }; void Test(void) { A *p; { A a; p = &a; // 注意 a 的生命期 } p->Func(); // p 是“野指针” } 函数 Test 在执行语句 p->Func() 时 ,对象 a 已经消失,而 p 是指向 a 的,所以 p 就成了 “野指针”。 但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。 |
相关文章推荐
- 高质量C++编程指南 》学习重点四
- 《 高质量C++编程指南 》学习重点六
- 《 高质量C++编程指南 》学习重点七
- 《 高质量C++编程指南 》学习重点八
- 《 高质量C++编程指南 》学习重点九
- 《 高质量C++编程指南 》学习重点十
- 《 高质量C++编程指南 》学习重点十一
- 高质量C++编程指南学习笔记1-2章---thanks to林锐
- 高质量C++编程指南学习笔记3-4章---thanks to林锐
- 高质量C++编程指南学习笔记5-6章---thanks to林锐
- 高质量C++编程指南学习小结
- 高质量C++编程指南学习笔记第7章---thanks to林锐
- 高质量C++编程指南学习笔记
- 高质量C++编程指南学习笔记第9章---thanks to林锐
- 高质量C++编程指南学习笔记第8章---thanks to林锐
- 高质量C++编程指南学习笔记第10章---thanks to林锐
- 高质量C++编程指南学习笔记第11章---thanks to林锐
- 学习高质量的c编程指南(程序的板式)
- 学习笔记之高质量C++/C编程指南
- 高质量的c++编程指南