不常见的数据类型
所谓不常见的数据类型,就是在现代的面向对象的编程中不提倡从而不常见的类型。主要有三种:结构体(structure), 指针(pointer), 和全局变量。
结构体
结构体相对来说还是比较简单,它可以看做是只有公有成员变量的类。其主要用途就是把相关联的数据组织到一起,可以把大堆的数据分组;可以简化对一大块数据的操作,比如复制,交换;可以简化参数列表;从而简化了维护的工作。当然,也可以考虑用类来实现。
指针
指针号称是初学编程的人最难于理解和掌握的概念,也是代码中最容易出错的地方,而且是那种很难定位的错误,所以有些编程语言像Java,C#都不提供指针类型。这也是把它放到不常见的数据类型里的原因。但是只要用好,它也是很强大的工具。所以要谨慎使用。
从概念上来讲,一个指针包含两部分的信息:一是它指向一个内存区域;二是应该怎么解释它指向的区域的内容。所以,任何使用和错误都应该从这两个方向去考虑。问题来了,它指向哪,指的范围有多大,它在哪里初始化,它会不会指错了地方,会不会超出了界限,它需要指向这个区域多久,释放的时候它还指向这个地方吗,重复释放会怎样,这么解释指向的内容对不对,等等。如果这些问题你都清楚了,那么你应该把理解指针了,如果不清楚,在用之前请搞清楚。
因为指针容易出错,所以我们有很多方法去减小这种几率。比如隔离,只在小范围内使用;比如使用前,使用中,使用后的各种检查清理,或者实时追踪;比如用一些自动指针,智能指针,或者自己实现一个类似功能的指针,更集中的处理所有指针的问题等等。基本上,按照checklist里列出来的检查一下吧。
全局变量
全局变量用起来很方便,可是用多了之后程序会越来越复杂,越来越容易出错,所以也不被提倡,被列为不得不用的时候才用的一种手段。为什么会这样呢,原因在于全局变量任何一段代码都可以访问,谁都可以改,改来改去就不知道谁在什么时候改了它的值,用的时候就发现不是想用的值,也就是访问控制没有做好。所以,一个很好的解决方法就是制定访问控制规则来管理全局变量。
一个常用的规则就是用访问控制函数。把一个全局变量改成一个类的static的变量,只能通过访问控制函数来访问它,不论是读还是写。在访问控制函数中可以做各种需要的处理,检查,判断,包括权限锁定,解锁。
如果还有实在不能不用全局变量的情况,也还有几点可以尽量减小它的危害。比如制定规则让人一看就知道它是全局变量(像加一个g_的前缀);再如记录所有的全局变量,让自己和别人都可以参考;还比如不要用它记录中间结果等。
最后要说的是不要把所有的全局变量放在一个庞大的类里面来假装自己没有用全局变量,那样跟用了也没什么区别。方法规则什么的都是手段,目的是要降低程序的复杂性,增强可读性,应该好好思考哪些可以不用,哪些该用,该用的要用在哪里。
Over!附上checklist:
Checklist: Unusual Data Types
Structures
- Have you used structures instead of naked variables to organize and manipulate groups of related data?
- Have you considered creating a class as an alternative to using a structure?
Pointers
- Are pointer operations isolated in routines?
- Are pointer references valid, or could the pointer be dangling?
- Does the code check pointers for validity before using them?
- Is the variable that the pointer references checked for validity before it's used?
- Are pointers set to NULL after they're freed?
- Does the code use all the pointer variables needed for the sake of readability?
- Are pointers in linked lists freed in the right order?
- Does the program allocate a reserve parachute of memory so that it can shut down gracefully if it runs out of memory?
- Are pointers used only as a last resort, when no other method is available?
Global Data
- Are all variables local or class-scope unless they absolutely need to be global?
- Do variable naming conventions differentiate among local, class, and global data?
- Are all global variables documented?
- Is the code free of pseudoglobal data-mammoth objects containing a mishmash of data that's passed to every routine?
- Are access routines used instead of global data?
- Are access routines and data organized into classes?
- Do access routines provide a level of abstraction beyond the underlying data-type implementations?
- Are all related access routines at the same level of abstraction?