C++ STL编程轻松入门 5

2.2.3 第三版:惟美主义的杰做 ios

  事态的发展有时候总会趋向极端,这在那些惟美主义者当中犹是如此。首先声明,我并非一个惟美主义者,提供第二版程序的改进版,彻底是为了让你更深入的感觉到STL的魅力所在。在看完第三版以后,你会强烈感觉到这一点。或许你也会变成一个惟美主义者了,至少在STL方面。这应该不是个人错,由于决定权在你手里。下面咱们来看看这个绝版的C++程序。c++

// name:example2_3.cpp
// alias:aesthetic version

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;

void main(void)
{
	typedef vector<int>				int_vector;
	typedef istream_iterator<int>				istream_itr;
	typedef ostream_iterator<int>				ostream_itr;
	typedef back_insert_iterator< int_vector >	back_ins_itr;

	// STL中的vector容器
	int_vector num;

	// 从标准输入设备读入整数, 
	// 直到输入的是非整型数据为止
	copy(istream_itr(cin), istream_itr(), back_ins_itr(num));

	// STL中的排序算法
	sort(num.begin(), num.end());

	// 将排序结果输出到标准输出设备
	copy(num.begin(), num.end(), ostream_itr(cout, "\n"));
}

  在这个程序里几乎每行代码都是和STL有关的(除了main和那对花括号,固然还有注释),而且它包含了STL中几乎全部的各大部件(容器container,迭代器iterator, 算法algorithm, 适配器adaptor),惟一的遗憾是少了函数对象(functor)的身影。web

  还记得开头提到的一个典型系统所具备的基本特征吗?--输入+处理+输出。全部这些功能,在上面的程序里,仅仅是经过三行语句来实现的,其中每一行语句对应一种操做。对于数据的操做被高度的抽象化了,而算法和容器之间的组合,就像搭积木同样轻松自如,系统的耦合度被降到了极低点。这就是闪耀着泛型之光的STL的伟大力量。如此简洁,如此巧妙,如此神奇!就像魔术通常,以致于再一次让你摸不着头脑。怎么实现的?为何在看第二版程序的时候如此清晰的你,又坠入了五里雾中(窃喜)。算法

  请留意此处的标题(惟美主义的杰做),在实际环境中,你未必要作到这样完美。毕竟美好愿望的破灭,在生活中时常会发生。过于理想化,并非一件好事,至少我是这么认为的。正如前面提到的,这个程序只是为了展现STL的独特魅力,你不得不为它的出色表现所折服,也许只有深谙STL之道的人才会想出这样的玩意儿来。若是你只是通常性的使用STL,作到第二版这样的程度也就能够了。数组

  实在是由于这个程序太过"简单",以致于我没法确定,在你尚未彻底掌握STL以前,经过个人讲解,是否可以领会这区区三行代码,我将尽个人最大努力。函数

  前面提到的迭代器能够对容器内的任意元素进行定位和访问。在STL里,这种特性被加以推广了。一个cin表明了来自输入设备的一段数据流,从概念上讲它对数据流的访问功能相似于通常意义上的迭代器,可是C++中的cin在不少地方操做起来并不像是一个迭代器,缘由就在于其接口和迭代器的接口不一致(好比:不能对cin进行++运算,也不能对之进行取值运算--即*运算)。为了解决这个矛盾,就须要引入适配器的概念。istream_iterator即是一个适配器,它将cin进行包装,使之看起来像是一个普通的迭代器,这样咱们就能够将之做为实参传给一些算法了(好比这里的copy算法)。由于算法只认得迭代器,而不会接受cin。对于上面程序中的第一个copy函数而言,其第一个参数展开后的形式是:istream_iterator(cin),其第二个参数展开后的形式是:istream_iterator()(若是你对typedef的语法不清楚,能够参考有关的c++语言书籍)。其效果是产生两个迭代器的临时对象,前一个指向整型输入数据流的开始,后一个则指向"pass-the-end value"。这个函数的做用就是将整型输入数据流从头到尾逐一"拷贝"到vector这个准整型数组里,第一个迭代器从开始位置每次累进,最后到达第二个迭代器所指向的位置。或许你要问,若是那个copy函数的行为真如我所说的那样,为何不写成以下这个样子呢?组件化

copy(istream_iterator<int>(cin), istream_iterator<int>(), num.begin());


  你确实能够这么作,可是有一个小小的麻烦。还记得初版程序里的那个数组越界问题吗?若是你这么写的话,就会遇到相似的麻烦。缘由在于copy函数在"拷贝"数据的时候,若是输入的数据个数超过了vector容器的范围时,数据将会拷贝到容器的外面。此时,容器不会自动增加容量,由于这只是简单地拷贝,并非从末端插入。为了解决这个问题,另外一个适配器back_insert_iterator登场了,它的做用就是引导copy算法每次在容器末端插入一个数据。程序中的那个back_ins_itr(num)展开后就是:back_insert_iterator

  终于将讲完了三分之一(真不容易!),好在第二句和前一版程序没有差异,这里就略过了。至于第三句,ostream_itr(cout, "\n")展开后的形式是:ostream_iterator(cout, "\n"),其效果是产生一个处理输出数据流的迭待器对象,其位置指向数据流的起始处,而且以"\n"做为分割符。第二个copy函数将会从头到尾将vector中的内容"拷贝"到输出设备,第一个参数所表明的迭代器将会从开始位置每次累进,最后到达第二个参数所表明的迭代器所指向的位置。spa

  这就是所有的内容。code

  2.3 历史的评价orm

  历史的车轮老是滚滚向前的,工业时代的文明较之史前时代,固然是先进而且发达的。回顾那两个时代的C++程序,你会真切的感觉到这种差异。简洁易用,具备工业强度,较好的可移植性,高效率,加之第三个使人目眩的绝版程序所体现出来的高度抽象性,高度灵活性和组件化特性,使你对STL背后所蕴含的泛型化思想都有了些微的感觉。

  真幸运,你能够横跨两个时代,有机会目击这种"文明"的差别。同时,这也应该使你越加坚决信念,使本身顺应时代的潮流。

  2.2.3 第三版:惟美主义的杰做 

  事态的发展有时候总会趋向极端,这在那些惟美主义者当中犹是如此。首先声明,我并非一个惟美主义者,提供第二版程序的改进版,彻底是为了让你更深入的感觉到STL的魅力所在。在看完第三版以后,你会强烈感觉到这一点。或许你也会变成一个惟美主义者了,至少在STL方面。这应该不是个人错,由于决定权在你手里。下面咱们来看看这个绝版的C++程序。

// name:example2_3.cpp
// alias:aesthetic version

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;

void main(void)
{
	typedef vector<int>				int_vector;
	typedef istream_iterator<int>				istream_itr;
	typedef ostream_iterator<int>				ostream_itr;
	typedef back_insert_iterator< int_vector >	back_ins_itr;

	// STL中的vector容器
	int_vector num;

	// 从标准输入设备读入整数, 
	// 直到输入的是非整型数据为止
	copy(istream_itr(cin), istream_itr(), back_ins_itr(num));

	// STL中的排序算法
	sort(num.begin(), num.end());

	// 将排序结果输出到标准输出设备
	copy(num.begin(), num.end(), ostream_itr(cout, "\n"));
}

  在这个程序里几乎每行代码都是和STL有关的(除了main和那对花括号,固然还有注释),而且它包含了STL中几乎全部的各大部件(容器container,迭代器iterator, 算法algorithm, 适配器adaptor),惟一的遗憾是少了函数对象(functor)的身影。

  还记得开头提到的一个典型系统所具备的基本特征吗?--输入+处理+输出。全部这些功能,在上面的程序里,仅仅是经过三行语句来实现的,其中每一行语句对应一种操做。对于数据的操做被高度的抽象化了,而算法和容器之间的组合,就像搭积木同样轻松自如,系统的耦合度被降到了极低点。这就是闪耀着泛型之光的STL的伟大力量。如此简洁,如此巧妙,如此神奇!就像魔术通常,以致于再一次让你摸不着头脑。怎么实现的?为何在看第二版程序的时候如此清晰的你,又坠入了五里雾中(窃喜)。

  请留意此处的标题(惟美主义的杰做),在实际环境中,你未必要作到这样完美。毕竟美好愿望的破灭,在生活中时常会发生。过于理想化,并非一件好事,至少我是这么认为的。正如前面提到的,这个程序只是为了展现STL的独特魅力,你不得不为它的出色表现所折服,也许只有深谙STL之道的人才会想出这样的玩意儿来。若是你只是通常性的使用STL,作到第二版这样的程度也就能够了。

  实在是由于这个程序太过"简单",以致于我没法确定,在你尚未彻底掌握STL以前,经过个人讲解,是否可以领会这区区三行代码,我将尽个人最大努力。

  前面提到的迭代器能够对容器内的任意元素进行定位和访问。在STL里,这种特性被加以推广了。一个cin表明了来自输入设备的一段数据流,从概念上讲它对数据流的访问功能相似于通常意义上的迭代器,可是C++中的cin在不少地方操做起来并不像是一个迭代器,缘由就在于其接口和迭代器的接口不一致(好比:不能对cin进行++运算,也不能对之进行取值运算--即*运算)。为了解决这个矛盾,就须要引入适配器的概念。istream_iterator即是一个适配器,它将cin进行包装,使之看起来像是一个普通的迭代器,这样咱们就能够将之做为实参传给一些算法了(好比这里的copy算法)。由于算法只认得迭代器,而不会接受cin。对于上面程序中的第一个copy函数而言,其第一个参数展开后的形式是:istream_iterator(cin),其第二个参数展开后的形式是:istream_iterator()(若是你对typedef的语法不清楚,能够参考有关的c++语言书籍)。其效果是产生两个迭代器的临时对象,前一个指向整型输入数据流的开始,后一个则指向"pass-the-end value"。这个函数的做用就是将整型输入数据流从头到尾逐一"拷贝"到vector这个准整型数组里,第一个迭代器从开始位置每次累进,最后到达第二个迭代器所指向的位置。或许你要问,若是那个copy函数的行为真如我所说的那样,为何不写成以下这个样子呢?

copy(istream_iterator<int>(cin), istream_iterator<int>(), num.begin());


  你确实能够这么作,可是有一个小小的麻烦。还记得初版程序里的那个数组越界问题吗?若是你这么写的话,就会遇到相似的麻烦。缘由在于copy函数在"拷贝"数据的时候,若是输入的数据个数超过了vector容器的范围时,数据将会拷贝到容器的外面。此时,容器不会自动增加容量,由于这只是简单地拷贝,并非从末端插入。为了解决这个问题,另外一个适配器back_insert_iterator登场了,它的做用就是引导copy算法每次在容器末端插入一个数据。程序中的那个back_ins_itr(num)展开后就是:back_insert_iterator

  终于将讲完了三分之一(真不容易!),好在第二句和前一版程序没有差异,这里就略过了。至于第三句,ostream_itr(cout, "\n")展开后的形式是:ostream_iterator(cout, "\n"),其效果是产生一个处理输出数据流的迭待器对象,其位置指向数据流的起始处,而且以"\n"做为分割符。第二个copy函数将会从头到尾将vector中的内容"拷贝"到输出设备,第一个参数所表明的迭代器将会从开始位置每次累进,最后到达第二个参数所表明的迭代器所指向的位置。

  这就是所有的内容。

  2.3 历史的评价

  历史的车轮老是滚滚向前的,工业时代的文明较之史前时代,固然是先进而且发达的。回顾那两个时代的C++程序,你会真切的感觉到这种差异。简洁易用,具备工业强度,较好的可移植性,高效率,加之第三个使人目眩的绝版程序所体现出来的高度抽象性,高度灵活性和组件化特性,使你对STL背后所蕴含的泛型化思想都有了些微的感觉。

  真幸运,你能够横跨两个时代,有机会目击这种"文明"的差别。同时,这也应该使你越加坚决信念,使本身顺应时代的潮流。

相关文章
相关标签/搜索