文档章节

C++ STL编程轻松入门 5

暖冰
 暖冰
发布于 2015/11/21 10:33
字数 3547
阅读 59
收藏 8

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背后所蕴含的泛型化思想都有了些微的感受。

  真幸运,你可以横跨两个时代,有机会目睹这种"文明"的差异。同时,这也应该使你越加坚定信念,使自己顺应时代的潮流。

  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背后所蕴含的泛型化思想都有了些微的感受。

  真幸运,你可以横跨两个时代,有机会目睹这种"文明"的差异。同时,这也应该使你越加坚定信念,使自己顺应时代的潮流。


本文转载自:http://tech.163.com/05/0613/10/1M4EA0US00091589_5.html

暖冰
粉丝 57
博文 124
码字总数 116908
作品 1
美国
程序员
私信 提问
VS2010/MFC编程入门教程之目录和总结(鸡啄米)

鸡啄米的这套VS2010/MFC编程入门教程到此就全部完成了,虽然有些内容还未涉及到,但帮助大家进行VS2010/MFC的入门学习业已足够。以此教程的知识为基础,学习VS2010/MFC较为深入的内容已非难事...

weixin_40647819
2018/05/23
0
0
《鸡啄米C++编程入门系列》系列技术文章整理收藏

《鸡啄米C++编程入门系列》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201812.html 文章 鸡啄米:C++编程入门系列之前言 鸡啄米:C++编程入门系列之一(进制...

开元中国2015
2015/06/27
85
0
C++各阶段学习书目

1. 入门 Lippman的《Essential C++》 顾名思义,这本书是很短小精悍的。通过这本书,可以对C++的最常用和重要的特性有全面的了解,并对C++的全貌有一个概念。虽然这远远不够,但就是这样的书...

晨曦之光
2012/04/24
471
1
c语言编程软件有哪些 Win7下用哪种C语言编译器

C语言是一门历史很长的编程语言,其编译器和开发工具也多种多样,其开发工具包括编译器,现举几个开发工具供大家选择,当然也要根据自己的操作系统来选择适合自己的开发工具 好多刚开始接触c...

mini92
2018/04/20
0
0
为什么要选择学习C/C++语言?怎么学习C/C++语言?

为什么要选择学习C/C++语言? 这几年,随着智能设备不断增多及物联网的飞速发展,企业对C/C++人才的需求量呈现出了爆炸式增长。由于C/C++相对于JAVA、.NET、PHP语言入门较难,因此选择学习C/C...

八一戒
2013/08/01
897
4

没有更多内容

加载失败,请刷新页面

加载更多

Redis集群搭建

服务器资源 ip 账号 配置 操作系统 xxx.70 root/xxx 磁盘50G(/)+150G(/home)、内存16G、CPU 16core CentOS Linux release 7.2.1511 (Core) xxx.74 root/xxx 磁盘50G(/)+150G(/home)、......

jxlgzwh
9分钟前
2
0
avro

一、 ```我们已经接触过很多序列化框架(或者集成系统),比如protobuf、hessian、thrift等,它们各有优缺点以及各自的实用场景,Avro也是一个序列化框架,它的设计思想、编程模式都和thi...

hexiaoming123
11分钟前
3
0
QML TextInput的字体超出控件范围

本文链接:https://blog.csdn.net/chyuanrufeng/article/details/54691998 问题描述 :QML TextInput输入内容超过TextInput的大小 当输入过多的字符串时,会出现内容超过TextInput的大小,字...

shzwork
13分钟前
1
0
《Java 8 in Action》Chapter 10:用Optional取代null

1965年,英国一位名为Tony Hoare的计算机科学家在设计ALGOL W语言时提出了null引用的想法。ALGOL W是第一批在堆上分配记录的类型语言之一。Hoare选择null引用这种方式,“只是因为这种方法实...

HelloDeveloper
13分钟前
1
0
进击的 Java ,云原生时代的蜕变

作者| 易立 阿里云资深技术专家<br /> <br />导读:云原生时代的来临,与Java 开发者到底有什么联系?有人说,云原生压根不是为了 Java 存在的。然而,本文的作者却认为云原生时代,Java 依然...

阿里巴巴云原生
16分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部