您的位置:首页 > 文旅 > 旅游 > 广州设计事务所_浏览器编程语言_百度网站制作联系方式_搜索引擎排名大全

广州设计事务所_浏览器编程语言_百度网站制作联系方式_搜索引擎排名大全

2025/1/9 15:50:22 来源:https://blog.csdn.net/2302_80220453/article/details/144790180  浏览:    关键词:广州设计事务所_浏览器编程语言_百度网站制作联系方式_搜索引擎排名大全
广州设计事务所_浏览器编程语言_百度网站制作联系方式_搜索引擎排名大全

标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。虽说它主要出现到C++中,但在被引入C++之前该技术就已经存在了很长时间。STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。

目录

1.STL简介

2. 标准库中的string类

2.1 string类

string的构造函数

遍历字符串

迭代器

auto关键字

3.string内的一些方法

size和length

capacity

reserve

clear

 resize

operate[]和at

push_back和append

  insert

 erase

c_str


1.STL简介

STL(Standard Template Library)标准模板库是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架

STL也是C语言和C++的重大区分之一,有了STL,C++就不用再手动的实现顺序表,链表,哈希表等等的数据结构,而C语言还必须手动实现,十分的繁琐

STL的六大组件:

STL需要我们在实践中不断的使用,不断的积累才能渐渐的掌握。 

我们下面将学习几个STL中重要的数据结构。

2. 标准库中的string类

首先阐述一个知识点,在C++中string的结尾是不包含'\0'的,string不依赖于'\0'来判断字符串的末尾,而是在类内会有成员变量_size来记录长度。

2.1 string类

严格来说,string 并不属于STL的,而是属于C++标准库

由于编码的原因,其实string是被typedef出来的,原生类型为basic_string<char>

字符型除了char还有char16_t,wchar_t

在使用string类时,必须包含#include头文件<string>以及using namespace std;

string的构造函数

string有七个构造函数,一般我们指挥使用 1 2 4 三个构造函数

 string重载了流插入和流提取,可以直接输入输出

下面我们来看一下第3个构造函数

substring (3)
string (const string& str, size_t pos, size_t len = npos);

可以看到他的从str的第pos个位置拷贝len长度的字符 

 

那么如果我们输入的len比原字符串str长呢?

 文档中也描述了这种情况,会拷贝到str的尾部就停下来了,并没有报错

我们还观察到len的参数位置有一个缺省值npos,那么npos又是什么呢? 

我们可以从文档中找到npos的定义,它是string类中const 静态变量,大小是 整形的最大值,(size_t -1)大概是42亿九千万,即字符串基本不可能到达的值,故就将npos当作字符串的结尾。

第五个构造函数

from sequence (5)
string (const char* s, size_t n);

 就是拷贝字符串的前n个元素        

        第六个构造函数

fill (6)
string (size_t n, char c);

 即用n个字符c初始化

 

第七个构造函数和迭代器有关,我们先不讲。

而string的析构函数并不需要讲,因为会自动调用,底层就是自动构造的数组,在生命周期结束后会自动调用析构函数释放空间。

通过字符串是一个字符类数组,我们可以猜想string类内底层的成员变量应该是这个样子的

遍历字符串

我们遍历字符串有三种方式

第一种就是用下标+[]

	for (int i = 0; i < s1.size(); ++i){cout << s1[i] << " ";}cout << endl;
迭代器

第二种就是用迭代器

迭代器常规情况下有四种 iterator, reverse_iterator  , const_iterator  , const_reverse_iterator

迭代器广泛应用于STL类中,使用用法就是类域::iterator,如vector<int>::iterator,string::iterator

	string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;

我们可以发现迭代器看起来和指针一样,它有可能是指针实现的,但也不一定是指针实现的,不同平台有不同的实现。不过我们可以当作指针来用

可以说iterator是像指针的东西,但是不能说iterator就是指针

我们根据上面的代码可以推断一下

如果迭代器不是指针,那么代码中的*,和++符号就是通过运算符重载进行了修改其功能

如果是指针,*和++,和我们平常使用的指针类用法是一样的

迭代器nb之处它提供了一种通用的访问方式,所有的容器都可以通过iterator进行访问,如下举个例子。

        

 这就是迭代器的基本用法。

第三种就是C++11提供的范围for

所有的容器都支持范围for

	for (auto ch : s2){cout << ch << " ";}cout << endl;

auto关键词也是C++11的能根据对象自动推导类型

代码的意思就是一次取出来一个元素,自动推导,自动迭代,自动判断结束

范围for在底层的实现和迭代器遍历一样,实际上在编译过后,这段代码会被编译器自动换成迭代器的代码,因此我们才说所有的容器都支持范围for,因为支持范围for就是支持迭代器。

我们通过上面的代码,可以发现,迭代器是可以进行修改的,但是范围for,由于是通过ch自动提取元素,自动推导类型,实际上ch是取出元素的临时拷贝,修改ch是不会导致原字符串变化的。

如果我们想要通过范围for修改需要,添加引用&符号。


auto关键字
  • 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
  • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
  • auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
  • auto不能直接用来声明数组

auto真正的价值就是用来简化代码,我们之后会学到类型特别长的自定义类型,用来替换长类型

如我们之后要学习的哈希表

HTIterator<K, T,const T&,const T*, KeyOfT, Hash> ConstIterator;

通过模板类实现的迭代器,类型名很长,但是如果我们用auto自动推导的话,是不是就很方便了呢

auto ConstIterator = dict.begin();

但是auto在方便的同时,也会牺牲一定程度的代码可读性。 

3.string内的一些方法

size和length

string类中的这两个函数,其实作用都是一样的,但是为什么会出现两个一样的函数呢?

这点的原因就是由于历史发展的原因,string出现的时间要比STL出现的还要早一些。

如果我们去看标准的STL容器部分,狭义的说是不包括string的,只是从广义上来说,将string归为STL中更加的便于理解。

按道理来说string ,字符串长度用length非常的合理,在C语言中都是用length来标明字符串长度的,因此,length就加入了C++标准库内,但是后来STL出来之后,string也要兼容STL,因此就在string内又加入了size方法。

我们可能会想为什么不把length方法给删去了呢?

这个是不合理的,库的发展都是向前兼容的,不会轻易的删除方法,之前如果有程序用length进行编译的,在后来把length删了,程序无法编译,就出幺蛾子了。

这个点我们了解一下,length和size是一样的即可。

capacity

我们通过一段代码来了解一下,string的扩容是如何扩的。

代码如下

 这段代码的意思就是依次插入100个字符,容量满了就扩容并提示

在VS的编译器下,我们好像找不到扩容的规律,好像不是完全按2倍扩容的

而是第一次是二倍,后序基本上是按1.5倍扩容的

这是由于在VS下, 作了一个特殊的处理,当小于16时,它会将其存到内部数组的buffer里面,VS担心像这种小块数据全都存到堆上了,因此当数据量小的时候会将其放到内部数组里。

当小于16会存到数组内,当大于16时就将这个数组废弃了,转而存到指针指向的堆中。

我们看一下图就明白了。

 上面的是在VS下进行编译的,那么我们去linux用g++进行编译得到的结果又会不同,如下图所示

 

我们可以看到完全相同的程序,在不同的编译器下,扩容却出现了不同的结果

那有没有什么办法能够减少扩容呢?

reserve

reserve方法,让string对象提前开好空间,如果我知道有100个字符,我就开100的空间,这样就可以减少扩容,提高效率。

如果我们reserve100,在VS编译器中实际会开比100大的空间,来保证整数对齐。

而在不同平台中,扩容的空间也不同,比如在g++编译环境中,reserve100,那么g++就给你开100的空间。    

在VS中,如果我们用reserve传入的参数,比原有的容量要小,reserve是不会去缩容的。

而在g++中,是会缩容的。

这也是平台之间的差异,一定要注意

g++中选择珍惜空间,vs中选择以空间换时间。

clear

clear是只清理数据,但是不清理容量。

 resize

我们要从三种情况来解释resize(n)

假设原字符串内有10个数据 即size = 10,capacity = 20

当n<10时,会删除数据 ,缩不缩容不好说,要看平台的设计。

当10<n<20时 会在字符串末尾插入所传入的数据,若不传入数据,则会默认插入'\0'

当 n>20时,会扩容,并插入值。

operate[]和at

两个函数都是访问第i个的字符,差别在于operator[]处理越界,用的assert断言

而at处理越界用的是抛异常。

push_back和append

push_back函数只能插入字符,append可以尾插字符串

两个函数的方法看起来有很多,但是在实践中我们用的最多的还是 operator+= ,比较直观,而且很方便。 

我们真正要关注的两个接口还是insert和erase

  insert

真的感觉十分的复杂且冗余,但是这是由于历史发展的原因,我们也没有办法去改变,只要掌握几个较为实用的方法即可。

 erase

erase有三个实现,但是一般来说,我们用的是第一个

我们要注意erase()也提供了npos,直接删到结尾

所以如果我们想在删除某一个位置之后的全部字符,就不用传入参数,直接用缺省参数即可

void test_string6()
{string s("hello world");s.erase(6, 1);cout << s << endl;// 头删s.erase(0, 1);cout << s << endl;s.erase(s.begin());cout << s << endl;// 尾删s.erase(--s.end());cout << s << endl;s.erase(s.size() - 1, 1);cout << s << endl;string ss("hello world");ss.erase(6);cout << ss << endl;
}

c_str

返回值为c的一个字符串

c_str的函数是专门来兼容C语言

像mysql的函数,他所需的参数必须是char*,而我们C++习惯用string来写,那么传入参数时,就可以调用c_str函数 ,来转换类型。

如下所示,便是例子         

剩下还有很多函数,在实践中是基本用不到的,如果用到了,我们可以去文档里自己查一下用法,还是那句话,由于历史的原因,string类所包含的函数过于冗余了,很多的函数都是重复且实际用处很小的,我们了解即可。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com