1.初识STL
1.什么是STL
STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架
2.STL的版本
- 原始版本
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。 HP 版本–所有STL实现版本的始祖
- P.J.版本
由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,缺陷:可读性比较低,符号命名比较怪异
- RW版本
由Rouge Wage公司开发,继承自HP版本,被C+ + Builder 采用,不能公开或修改,可读性一般
- SGI版本
由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版 本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。我们后面学习STL要阅读部分源代码,主要参考的就是这个版本
3.STL的六大组件
对于STL的学习,这里推荐一个网站cplusplus.com
2.string
接下来就要正式进入到对STL的学习中啦,在对STL的学习过程中,需要注意的是
第一、熟悉库里面的STL的各种类模板的常用接口
第二、尝试去模拟实现库里面的类模板
注:在过程中,我们可能会遇到一些没有办法解决的问题,此时将会去查库里的源码,由于各个库中的实现方式不太一样,所以,在这里定一下,我们将会参考SGI版本的代码,结合侯捷老师的STL源码剖析去模拟实现。
1.string类模板
我们打开上文中推荐的网站,搜索string,会发现我们平常用的string其实是basic_string<char>,是类模板basic_string实例化出来的char类。
basic_string是一个类模板,可以通过传入不同的类型参数实例化出不同的类。
那么,对于string,为什么要使用一个类模板呢,在C语言中,对于字符串都是能够存放char类型的数据就可以了?
这是因为编码的问题,我们知道,在计算机中存放的数据都是0和1,为了让数据转换成人能看懂的东西,人们把特定的01序列给定义成某个字符,按照这种方式可以将计算机中的数据翻译出来,这就是编码,最初的编码方式就是将一些符号和大小写的26个字母与01序列对应,这就是ASCII码。
现在的常见编码方式
- ASCII码
美国信息交换标准代码,是计算机存值和文字符号的对应关系,只有256个字符
- Unicode
万国码,是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码包括了utf-8,utf-16,utf-32
utf-8兼容了ASCII,utf-8使用比较普遍,也比较节省空间
- gbk
gbk即国标,针对中文而设计的编码,采用双字节编码
2.string类的构造函数
首先,一个类中必不可少的就是构造函数,我们来看一下string类的构造函数有什么
以上就是string的所有构造函数了,接下来让我们通过代码来实验一下:
void Test_Construct() { char str[] = "hello string";//创建一个C语言的字符串 string s1;//默认构造函数,不用传递任何参数,最终是s1中只有一个\0 string s2(str);//使用C语言的字符串构造一个string类型的对象 string s3(s2);//使用s2拷贝构造一个string类型的对象 string s4(s3, 2, 5);//使用s3中的第二个位置开始长度为5的子串构造对象 string s5(str, 8);//使用C语言的字符串构造一个指定长度的string类型 string s6(10, 'a');//使用指定字符构造一个长度为10,内容为a的对象 auto first = s2.begin(); auto last = s2.end(); string s7(first, last);//使用迭代器区间构造一个[first,last)的对象 cout << "s1: " << s1 << endl; cout << "s2: " << s2 << endl; cout << "s3: " << s3 << endl; cout << "s4: " << s4 << endl; cout << "s5: " << s5 << endl; cout << "s6: " << s6 << endl; cout << "s7: " << s7 << endl; }
运行上述代码,结果是:
在上面的函数原型中,好像发现了一个之前没见过的东西,npos
,什么是npos呢?查一下文档
可以看到npos是在类中定义的一个公共的静态成员常量,这个常量定义的值为-1,但是由于常量的类型是size_t,即unsigned int,所以表示的此类型可能的最大值。我们理解成字符串的结尾即可。
由于npos是string类中的成员常量,所以在使用npos的时候需要指定类域,即string::npos
.
3.string内部数据访问
可以看到,对于数据访问,string提供了4个接口,其中两个是C++11新增的,看名字也可以得出,是获得字符串首元素和最后一个元素的,不常用,所以在此不过多赘述。我们主要关注at和operator[]这两个接口。
这两个接口都是能够拿到指定位置的值,其中operator[]是对[]的运算符重载。可以看到两个接口都重载了普通版本和const版本,用来应对权限放大的问题。
void Test_Element() { string s = "hello string"; cout << s.at(4) << endl; cout << s[4] << endl; }