若是你是一个纯粹的实用主义者,也许一开始就能够从这里开始看起,由于此处提供了一个示例程序,它能够带给你有关使用STL的最直接的感觉。是的,与其纸上谈兵,不如单刀直入,实际操做一番。可是,须要提醒的是,假如你在兴致昂然地细细品味本章内容的时候,可以同时结合前面章节做为佐餐,那将是再好不过的。你会发现,前面所提到的有关STL的那些优势,在此处获得了确切的应证。本章的后半部分,将为你演示在一些主流C++编译器上,运行上述示例程序的具体操做方法,和须要注意的事项。web
很是遗憾,我不得不舍弃"Hello World"这个经典的范例,尽管它不仅一次的被各类介绍计算机语言的教科书所引用,几乎成为了一个默认的“标准”。其缘由在于它太过简单了,以致于不具有表明性,没法展示STL的巨大魅力。我选用了一个稍稍复杂一点的例子,它的大体功能是:从标准输入设备(通常是键盘)读入一些整型数据,而后对它们进行排序,最终将结果输出到标准输出设备(通常是显示器屏幕)。这是一种典型的处理方式,程序自己具有了一个系统所应该具备的几乎全部的基本特征:输入 + 处理 + 输出。你将会看到三个不一样版本的程序。第一个是没有使用STL的普通C++程序,你将会看到完成这样看似简单的事情,须要花多大的力气,并且还未必没有一点问题(真是吃力不讨好)。第二个程序的主体部分使用了STL特性,此时在第一个程序中所遇到的问题就基本能够解决了。同时,你会发现采用了STL以后,程序变得简洁明快,清晰易读。第三个程序则将STL的功能发挥到了及至,你能够看到程序里几乎每一行代码都是和STL相关的。这样的机会并不老是随处可见的,它展示了STL中的几乎全部的基本组成部分,尽管这看起来彷佛有点过度了。数组
有几点是须要说明的:框架
这个例程的目的,在于向你演示如何在C++程序中使用STL,同时但愿经过实践,证实STL所带给你的确确实实的好处。程序中用到的一些STL基本组件,好比:vector(一种容器)、sort(一种排序算法),你只须要有一个大体的概念就能够了,这并不影响阅读代码和理解程序的含义。函数
不少人对GUI(图形用户界面)的运行方式很感兴趣,这也难怪,漂亮的界面老是会使人赏心悦目的。可是很惋惜,在这里没有加入这些功能。这很容易解释,对于所提供的这个简单示例程序而言,加入GUI特性,是有点本末倒置的。这将会使程序的代码量骤然间急剧膨胀,而真正能够说明问题的核心部分确被淹没在诸多可有可无的代码中间(你须要花去极大的精力来处理键盘或者鼠标的消息响应这些繁琐而又较为规范的事情)。即便你有像Borland C++ Builder这样的基于IDE(集成化开发环境)的工具,界面的处理变得较为简单了(框架代码是自动生成的)。请注意,咱们这里所谈及的是属于C++标准的一部分(STL的第一个字母说明了这一点),它不涉及具体的某个开发工具,它是几乎在任何C++编译器上都能编译经过的代码。毕竟,在Microsoft Visual C++和Borland C++ Builder里,有关GUI的处理代码是不同的。若是你想了解这些GUI的细节,这里恐怕没有你但愿获得的答案,你能够寻找其它相关书籍。工具
在STL尚未降生的"黑暗时代",C++程序员要完成前面所提到的那些功能,须要作不少事情(不过这比起C程序来,彷佛好一点),程序大体是以下这个样子的:ui
// name:example2_1.cpp // alias:Rubish #include <stdlib.h> #include <iostream.h> int compare(const void *arg1, const void *arg2); void main(void) { const int max_size = 10; // 数组容许元素的最大个数 int num[max_size]; // 整型数组 // 从标准输入设备读入整数,同时累计输入个数, // 直到输入的是非整型数据为止 int n; for (n = 0; cin >> num[n]; n ++); // C标准库中的快速排序(quick-sort)函数 qsort(num, n, sizeof(int), compare); // 将排序结果输出到标准输出设备 for (int i = 0; i < n; i ++) cout << num[i] << "\n"; } // 比较两个数的大小, // 若是*(int *)arg1比*(int *)arg2小,则返回-1 // 若是*(int *)arg1比*(int *)arg2大,则返回1 // 若是*(int *)arg1等于*(int *)arg2,则返回0 int compare(const void *arg1, const void *arg2) { return (*(int *)arg1 < *(int *)arg2) ? -1 : (*(int *)arg1 > *(int *)arg2) ? 1 : 0; }
这是一个和STL没有丝毫关系的传统风格的C++程序。由于程序的注释已经很详尽了,因此不须要我再作更多的解释。总的说来,这个程序看起来并不十分复杂(原本就没有太多功能)。只是,那个compare函数,看起来有点费劲。指向它的函数指针被做为最后一个实参传入qsort函数,qsort是C程序库stdlib.h中的一个函数。如下是qsort的函数原型:
void qsort(void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
看起来有点使人做呕,尤为是最后一个参数。大概的意思是,第一个参数指明了要排序的数组(好比:程序中的num),第二个参数给出了数组的大小(qsort没有足够的智力预知你传给它的数组的实际大小),第三个参数给出了数组中每一个元素以字节为单位的大小。最后那个长长的家伙,给出了排序时比较元素的方式(仍是由于qsort的智商问题)。
如下是某次运行的结果:
输入:0 9 2 1 5 输出:0 1 2 5 9 有一个问题,这个程序并不像看起来那么健壮(Robust)。若是咱们输入的数字个数超过max_size所规定的上限,就会出现数组越界问题。若是你在Visual C++的IDE环境下以控制台方式运行这个程序时,会弹出非法内存访问的错误对话框。
这个问题很严重,严重到足以使你开始从新审视这个程序的代码。为了弥补程序中的这一缺陷。咱们不得不考虑采用以下三种方案中的一种:
采用大容量的静态数组分配。
限定输入的数据个数。
采用动态内存分配。
第一种方案比较简单,你所作的只是将max_size改大一点,好比:1000或者10000。可是,严格讲这并不能最终解决问题,隐患仍然存在。假若有人足够耐心,仍是可使你的这个通过纠正后的程序崩溃的。此外,分配一个大数组,一般是在浪费空间,由于大多数状况下,数组中的一部分空间并无被利用。
再来看看第二种方案,经过在第一个for循环中加入一个限定条件,可使问题获得解决。好比:for (int n = 0; cin >> num[n] && n < max_size; n ++); 可是这个方案一样不甚理想,尽管不会使程序崩溃,但失去了灵活性,你没法输入更多的数。
看来只有选择第三种方案了。是的,你能够利用指针,以及动态内存分配妥善的解决上述问题,而且使程序具备良好的灵活性。这须要用到new,delete操做符,或者古老的malloc(),realloc()和free()函数。可是为此,你将牺牲程序的简洁性,使程序代码陡增,代码的处理逻辑也再也不像原先看起来那么清晰了。一个compare函数或许就已经令你不耐烦了,更况且要实现这些复杂的处理机制呢?很难保证你不会在处理这个问题的时候出错,不少程序的bug每每就是这样产生的。同时,你还应该感谢stdlib.h,它为你提供了qsort函数,不然,你还须要本身实现排序算法。若是你用的是冒泡法排序,那效率就不会很理想。……,问题真是愈来愈让人头疼了!
关于第一个程序的讨论就到此为止,若是你对第三种方案感兴趣的话,能够尝试着本身编写一个程序,做为思考题。这里就不许备再浪费笔墨去实现这样一个让人不甚愉快的程序了。