您现在的位置是:首页 >技术交流 >【剖析STL】String网站首页技术交流
【剖析STL】String
1.什么是STL?
标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。虽说它主要出现到C++中,但在被引入C++之前该技术就已经存在了很长时间。STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
-
🔥标准模板库是一个C++软件库,大量影响了C++标准程序库但并非是其的一部分。其中包含4个组件,分别为算法、容器、函数、迭代器。
-
🔥模板是C++程序设计语言中的一个重要特征,而标准模板库正是基于此特征。标准模板库使得C++编程语言在有了同Java一样强大的类库的同时,保有了更大的可扩展性。
1.1STL的缺陷:
- STL库的更新太慢了。这个得严重吐槽,上一版靠谱是C++98,中间的C++03基本一些修订。C++11出
来已经相隔了13年,STL才进一步更新。 - STL现在都没有支持线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的。
- STL极度的追求效率,导致内部比较复杂。比如类型萃取,迭代器萃取。
- STL的使用会有代码膨胀的问题,比如使用vector/vector/vector这样会生成多份代码,当然这是模板语
法本身导致的。
2.Stirng容器
2.1为什么需要学习String容器?
C语言中,字符串是以’ ’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,
但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可
能还会越界访问。
为了优化这个问题,我们引入了String容器。
2.2初始String:
string本身是一个类模板:
string就是char类型的数组,char类型一个字节
wstring是wchar类型的数组,wchar为两个字节
char16_t类型为2字节,char32_t为4个字节
- 🔥string是表示字符串的字符串类
- 🔥该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
- 🔥string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>
string; - 🔥不能操作多字节或者变长字符的序列。在使用string类时,必须包含#include头文件以及using namespace std;
2.3String类的常用接口说明(注意下面我只讲解最常用的接口)
2.3.1string类对象的常见构造:
- Strin在C++98下有以下几种构造函数:
第二种: string s3 = "hello world";
这里是一个const char*类型隐式转换成string类型
第三种: string s4(s3, 6, 3);
子字符串构造函数
-
🔥复制str中从字符位置pos开始并跨越len个字符的部分(如果str太短或len为string::npos,则复制到str的末尾)。
-
🔥第三个参数有缺省值,npos是无符号整形,-1代表整形最大值为42亿多
string s1;
string s2("hello world");
string s3 = "hello world";
string s4(s3, 6, 3);
string s5(s3, 6, 13);
cout << s5 << endl;
string s6(s3, 6);
cout << s6 << endl;
string s7("hello world", 5);
cout << s7 << endl;
string s8(10, '*');
cout << s8 << endl;
- 本部分会详细介绍以下几个构造函数:
(constructor)函数名称 | 功能说明 |
---|---|
string() (重点) | 构造空的string类对象,即空字符串 |
string(const char* s) (重点) | 用C-string来构造string类对象 |
string(size_t n, char c) | string类对象中包含n个字符c |
string(const string&s) (重点) | 拷贝构造函数 |
- string() (重点):
构造空的string类对象,即空字符串
这里的空字符串指的是连 都没有的
string s1(""); string s2();
- 🔥s1是只有 ,s2是连 都没有,s1的size和length都为0,capacity为15,s2没有size和length和capacity
- string(const char* s) (重点):
复制以s为指向的以空结尾的字符序列(C-string)。
int main()
{
const char* p = "aaaaa";
string s1(p);
cout <<s1 << endl;//aaaaa
return 0;
}
- string(size_t n, char c):
用字符c的n个连续副本填充字符串。
string s2(4, 'b'); cout << s2 << endl;//bbbb
- string(const string&s) (重点)
构造一个str的副本。
string s3(s2);
2.3.2string类对象的容量操作
- 本部分会介绍以下几个容器操作:
函数名称 | 功能说明 |
---|---|
size(重点) | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
empty (重点) | 检测字符串释放为空串,是返回true,否则返回false |
clear (重点) | 清空有效字符 |
reserve (重点) | 为字符串预留空间** |
resize (重点) | 将有效字符的个数该成n个,多出的空间用字符c填充 |
- size和length
size和length的效果是一样的,都是返回字符串的有效长度(不包括 )
注意
size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一
致,一般情况下基本都是用size()。
- capacity
- 🔥返回当前为字符串分配的存储空间的大小,以字节表示。
这个容量不一定等于字符串长度。它可以等于或大于,额外的空间允许对象在向字符串中添加新字符时优化其操作。
- 🔥注意,这个容量并没有假设字符串的长度有限制。当此容量耗尽并且需要更多容量时,对象会自动对其进行扩展(重新分配其存储空间)。字符串长度的理论限制由成员max_size给出。
在对象被修改的任何时候,字符串的容量都可以被改变,即使这种修改意味着减小大小或者容量没有耗尽(这与vector容器中对容量的保证相反)。
可以通过调用成员reserve(后面会介绍)显式地更改字符串的容量。
void Teststring1()
{
// 注意:string类对象支持直接用cin和cout进行输入和输出
string s("hello, xiaolu!!!");
cout << s.size() << endl;//13
cout << s.length() << endl;//13
cout << s.capacity() << endl;//15
cout << s << endl;
}
- 在Debug和Release版本下,编译器自动扩容情况:
void TestPushBack()
{
string s;
size_t sz = s.capacity();
cout << "making s grow:
";
cout << "capacity changed: " << sz << '
';
for (int i = 0; i < 100; ++i)
{
s.push_back('c');
if (sz != s.capacity())
{
sz = s.capacity();
cout << "capacity changed: " << sz << '
';
}
}
}
在debug和release版本下,我们发现编译器每次扩容1.5倍左右
- clear
clear()只是将string中有效字符清空,不改变底层空间大小。
这里的情况是指清空size和length,不改变capacity
void Teststring1()
{
// 注意:string类对象支持直接用cin和cout进行输入和输出
string s("hello, xiaolu!!!");
cout << s.size() << endl;//13
cout << s.length() << endl;//13
cout << s.capacity() << endl;//15
cout << s << endl;
// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
s.clear();
cout << s.size() << endl;//0
cout << s.capacity() << endl;//15
}
- resize (重点)
- 🔥将字符串大小调整为n个字符的长度。
如果n小于当前字符串长度,则将当前值缩短到前n个字符,删除第n个字符以外的字符。
如果n大于当前字符串长度,则通过在末尾插入尽可能多的字符来扩展当前内容,以达到n的大小。如果指定了c,则新元素被初始化为c的副本,否则,它们是值初始化的字符(空字符)。
- 🔥这里如果缩小有效字符,只改变size和length,不改变capacity
void Teststring1()
{
// 注意:string类对象支持直接用cin和cout进行输入和输出
string s("hello, xiaolu!!!");
s.clear();
cout << s.size() << endl;//0
cout << s.capacity() << endl;//15
// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
// “aaaaaaaaaa”
s.resize(10, 'a');
cout << s.size() << endl;//10
cout << s.capacity() << endl;//15
// 将s中有效字符个数增加到15个,多出位置用缺省值'