类型安全
优雅而有效的代码的关键点在于通过使用一个灵活并可扩展的类型系统达到的类型安全. C++0x 不能把 C++ 变得完全类型安全 - 那需要取缔数组, 未初始化指针, 联合, 窄类型转换, C 风格的连接, 以及更多. 而且这么做也会引起硬件存取上的问题, 那是许多嵌入式系统应用所需要的. 那么我们能做什么呢? 缺乏类型安全是很多正确性和性能问题的根源. 例如:
void get_input(char* p)
{
char ch;
while (cin.get(ch) && !iswhite(ch)) *p++ = ch;
*p = 0;
}
那会使你脊背发凉; 实在是很吓人的. 类似的, 如果你关心性能, 你应该很不满意这种风格的通用链表:
struct Link {
Link* link;
void* data;
};
void my_clear(Link* p, int sz) // clear data of size sz
{
for (Link* q = p; q!=0; q = q->link) memset(q->data,0,sz);
}
那我们能做什么? 基本上, 我们能做的所有就是为这些不安全的实现提供另一种选择以及相关的工具 (类似 lint, 但具有更好的 C++ 类型系统的知识) 来检测不安全 ("传统的") 使用方式. 例如:
string s;
cin >> s;
这种方式完全避免了原来底层而且体积大的 get_input() 带来的问题, 同时更容易使用并且 (至少可能) 一样快. 类似地:
template<class In> void my_stl_clear(In first, In last)
{
while (first!=last) *first++ = 0;
}
这是 my_clear() 的一个完全的替换. my_clear() 有什么问题吗? 它比 my_stl_clear() 长, 不过当我们考虑性能时这不是问题所在. 问题在于缺乏类型信息. Link::data 是一个 void*, 所以它可以指向任何内存地址. 这意味着编译器必须假设对 q->data 的写 (在 memset() 里) 可能改变 *(q->ink) 的内容, 甚至是 q->link 本身. 这基本上阻止了优化器的工作. 如果是 link 和 data 有不同的静态类型, 编译器可以假设他们不会是别名. 所以, 对于一个正常的优化器生成的代码, my_stl_clear() 运行得比 my_clear() 快几倍. 另外, memset() 的使用是我们通过 void* 来存取数据所做的 workaround 的一个例子: 我们通常以一个函数甚至一个间接调用的函数结尾.那个, 也是很昂贵的[4].
定位由于缺乏类型安全而引起的问题的最直接的方法就是提供一个有边界检查的标准库, 基于静态类型的容器, 而且要在这个基础上进行 C++ 教学. 这样不会消除所有类型错误 - 总是会有决定要写 "手写的基本类型" 风格的程序员的, 也总会有程序员必须 (由于各种各样的原因) 在交付时关闭类型检查的的, 而且还有很多很多领域是标准库所无法覆盖到的. 最后一个问题会由标准库通过设定一个其他库所需要遵循的标准来解决.
系统化地使用具有边界检查的标准库版本意味着系统化地使用 exception, 这对于非严格实时要求的代码是可以的. 当前我们知道怎样对付 exception (例如, 请参见 [5] 的附录 E).
总结一下: C++0x 不可能堵住 C++ 类型系统里的所有弹孔, 但是它不会引入新的漏洞, 并且, 它会提供避免本身的不安全功能的方法 - 主要通过标准库来提供 (编译期或者运行期) 类型安全的替代品.
若你在年轻时上过水木, 它会一生跟随着你, 如一场浮动的盛宴
禁色和禁果仍被保存吗?
这世界有否给潜移默化?
离过家回了家仍住中环吗?
-----信有带到新居里烧吗?
一切美好的都会消失
人要是没有理想, 跟咸鱼有什么两样?
“把人们引向艺术和科学的最强烈动机之一,是要逃避日常生活中令人厌恶的粗俗和使人绝望的沉闷,是要摆脱人们自己反复无常的欲望的桎梏。一个修养有素的人总是渴望逃避个人生活而进入客观直觉和思维的世界。”
不要忘了,这个世界穿透一切高墙的东西,它就在我们的内心深处,他们无法达到,也接触不到,那就是希望。(FROM《肖申克的救赎》)