【剖析STL】String

这篇具有很好参考价值的文章主要介绍了【剖析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一样强大的类库的同时,保有了更大的可扩展性。

【剖析STL】String

1.1STL的缺陷:

  1. STL库的更新太慢了。这个得严重吐槽,上一版靠谱是C++98,中间的C++03基本一些修订。C++11出
    来已经相隔了13年,STL才进一步更新。
  2. STL现在都没有支持线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的。
  3. STL极度的追求效率,导致内部比较复杂。比如类型萃取,迭代器萃取。
  4. STL的使用会有代码膨胀的问题,比如使用vector/vector/vector这样会生成多份代码,当然这是模板语
    法本身导致的。

2.Stirng容器

2.1为什么需要学习String容器?

C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,
但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可
能还会越界访问。

为了优化这个问题,我们引入了String容器。

2.2初始String:

string本身是一个类模板:

【剖析STL】String

string就是char类型的数组,char类型一个字节

wstring是wchar类型的数组,wchar为两个字节

char16_t类型为2字节,char32_t为4个字节

【剖析STL】String

  • 🔥string是表示字符串的字符串类
  • 🔥该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  • 🔥string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>
    string;
  • 🔥不能操作多字节或者变长字符的序列。在使用string类时,必须包含#include头文件以及using namespace std;

【剖析STL】String

2.3String类的常用接口说明(注意下面我只讲解最常用的接口)

2.3.1string类对象的常见构造:
  • Strin在C++98下有以下几种构造函数:

【剖析STL】String

第二种: string s3 = "hello world";

这里是一个const char*类型隐式转换成string类型

第三种: string s4(s3, 6, 3);

子字符串构造函数

  • 🔥复制str中从字符位置pos开始并跨越len个字符的部分(如果str太短或len为string::npos,则复制到str的末尾)。

  • 🔥第三个参数有缺省值,npos是无符号整形,-1代表整形最大值为42亿多

【剖析STL】String

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;

【剖析STL】String

  • 本部分会详细介绍以下几个构造函数:
(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类对象,即空字符串

这里的空字符串指的是连\0都没有的

string s1(""); string s2();

  • 🔥s1是只有\0,s2是连\0都没有,s1的size和length都为0,capacity为15,s2没有size和length和capacity

【剖析STL】String

  • 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

【剖析STL】String

  • 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的效果是一样的,都是返回字符串的有效长度(不包括\0)

注意

size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一
致,一般情况下基本都是用size()。

  • capacity

【剖析STL】String

  • 🔥返回当前为字符串分配的存储空间的大小,以字节表示。

这个容量不一定等于字符串长度。它可以等于或大于,额外的空间允许对象在向字符串中添加新字符时优化其操作。

  • 🔥注意,这个容量并没有假设字符串的长度有限制。当此容量耗尽并且需要更多容量时,对象会自动对其进行扩展(重新分配其存储空间)。字符串长度的理论限制由成员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:\n";
	cout << "capacity changed: " << sz << '\n';
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

在debug和release版本下,我们发现编译器每次扩容1.5倍左右

【剖析STL】String

  • clear

clear()只是将string中有效字符清空,不改变底层空间大小。

这里的情况是指清空size和length,不改变capacity

【剖析STL】String

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 (重点)

【剖析STL】String

  • 🔥将字符串大小调整为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个,多出位置用缺省值'\0'进行填充
	// "aaaaaaaaaa\0\0\0\0\0"
	// 注意此时s中有效字符个数已经增加到15个
	s.resize(15);
	cout << s.size() << endl;//15
	cout << s.capacity() << endl;//15
	cout << s << endl;

	// 将s中有效字符个数缩小到5个
	s.resize(5);
	cout << s.size() << endl;//5
	cout << s.capacity() << endl;//15
	cout << s << endl;
}
  • reserve (重点)

【剖析STL】String

  • 🔥reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于
    string的底层空间总大小时,reserver不会改变容量大小。
  • 🔥 利用reserve提高插入数据的效率,避免增容带来的开销
void Teststring2()
{
	string s;
	// 测试reserve是否会改变string中有效元素个数
	s.reserve(100);
	cout << s.size() << endl;//0
	cout << s.capacity() << endl;//111

	// 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
	s.reserve(50);
	cout << s.size() << endl;//0
	cout << s.capacity() << endl;//111
}
  • empty

【剖析STL】String

这里必须要对象存在才可以调用,像string()出来的对象不存在,根本调用不了

【剖析STL】String

2.3.3string类对象的访问及遍历操作
函数名称 功能说明
operator[] (重点) 返回pos位置的字符,const string类对象调用
begin+ end begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭
代器
rbegin + rend begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭
代器
范围for C++11支持更简洁的范围for的新遍历方式
  • operator[] (重点)

我们在用字符数组的时候,我们经常用[]来访问字符,我们在stirng中同样可以这样使用

【剖析STL】String

  • 范围for

C++11支持更简洁的范围for的新遍历方式

void Teststring4()
{
	string s("hello xiaolu");
	for (size_t i = 0; i < s.size(); ++i)
		cout << s[i] << " ";
	cout << endl;
	for (auto ch : s)
		cout << ch << " ";
}
  • 迭代器和反向迭代器

迭代器(iterable)是一个超级接口! 是可以遍历集合的对象,为各种容器提供了公共的操作接口,隔离对容器的遍历操作和底层实现,从而解耦。

  • 🔥迭代器应该有4种,正向,反向,正向const,反向const

迭代器可以近似理解为指针,后面会详细讲解的

begin返回指向字符串开头的迭代器。

  • 🔥如果string对象是const限定的,该函数返回一个const_iterator。否则,它返回一个迭代器。

❓这里的const跟我们之前的const int i是不是一样的?

💡并不是,后者是一个关键字被修饰的不可以修改,前置是一个类型名称,被修饰的是这个迭代器指向的内容

end返回一个指向字符串末尾字符的迭代器。

rbegin和rend 跟begin和end完全相反

【剖析STL】String

void Teststring4()
{
	string s("hello xiaolu");
	string::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	// string::reverse_iterator rit = s.rbegin();
	// C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
	auto rit = s.rbegin();
	while (rit != s.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}
2.3.4string类对象的修改操作
函数名称 功能说明
push_back 在字符串后尾插字符c
append 在字符串后追加一个字符串
operator+= (重点) 在字符串后追加字符串str
c_str(重点) 返回C格式字符串
find + npos(重点) 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr 在str中从pos位置开始,截取n个字符,然后将其返回
  • push_back

将字符c添加到字符串的末尾,使其长度增加1。

string str; str.push_back(' '); // 在str后插入空格

  • append

【剖析STL】String

追加到字符串

通过在当前值的末尾添加额外的字符来扩展字符串:

void Teststring5()
{
	string str;
	str.push_back(' ');   // 在str后插入空格
	str.append("hello");  // 在str后追加一个字符"hello"
}
  • operator+= (重点)

在字符串后追加字符串str

void Teststring5()
{
	string str;
	str.push_back(' ');   // 在str后插入空格
	str.append("hello");  // 在str后追加一个字符"hello"
	str += 'x';           // 在str后追加一个字符'x'   
	str += "iaolu";          // 在str后追加一个字符串"iaolu"
	cout << str << endl;
	}
  • c_str(重点)

【剖析STL】String

获取C字符串等价项

  • 🔥返回一个指向数组的指针,该数组包含一个以空字符结尾的字符序列(即C-string),表示string对象的当前值。
void Teststring5()
{
	string str;
	str.push_back(' ');   // 在str后插入空格
	str.append("hello");  // 在str后追加一个字符"hello"
	str += 'x';           // 在str后追加一个字符'x'   
	str += "iaolu";          // 在str后追加一个字符串"iaolu"
	cout << str << endl;
	cout << str.c_str() << endl;   // 以C语言的方式打印字符串
	}
  • find + npos(重点)

【剖析STL】String

在字符串中搜索由其参数指定的序列的第一个匹配项。

  • 🔥当指定pos时,搜索只包含pos位置或之后的字符,忽略任何可能包含pos之前字符的情况。

  • 🔥请注意,与find_first_of成员不同的是,每当搜索多个字符时,仅匹配其中一个字符是不够的,必须匹配整个序列。

  • rfind

跟find完全相反,她从pos位置开始向前走

当指定pos时,搜索只包含从pos位置开始或之前的字符序列,忽略任何从pos位置之后开始的可能匹配。

  • substr

【剖析STL】String

生成子串,返回一个新构造的string对象,其值初始化为该对象的子字符串的副本。

  • 🔥子字符串是对象的一部分,从字符位置pos开始,跨越len字符(或直到字符串末尾,以哪个先到哪个)。
void Teststring5()
{
	string str;
	str.push_back(' ');   // 在str后插入空格
	str.append("hello");  // 在str后追加一个字符"hello"
	str += 'x';           // 在str后追加一个字符'x'   
	str += "iaolu";          // 在str后追加一个字符串"iaolu"
	cout << str << endl;
	cout << str.c_str() << endl;   // 以C语言的方式打印字符串

	// 获取file的后缀
	string file("string.cpp");
	size_t pos = file.rfind('.');
	string suffix(file.substr(pos, file.size() - pos));
	cout << suffix << endl;

	// npos是string里面的一个静态成员变量
	// static const size_t npos = -1;

	// 取出url中的域名
	string url("http://www.cplusplus.com/reference/string/string/find/");
	cout << url << endl;//http://www.cplusplus.com/reference/string/string/find/
	size_t start = url.find("://");
	if (start == string::npos)
	{
		cout << "invalid url" << endl;
		return;
	}
	start += 3;
	size_t finish = url.find('/', start);
	string address = url.substr(start, finish - start);
	cout << address << endl;//www.cplusplus.com

	// 删除url的协议前缀
	pos = url.find("://");
	url.erase(0, pos + 3);
	cout << url << endl;
}

注意:

  • 🔥在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般
    情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
  • 🔥对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
2.3.5string类非成员函数
函数 功能说明
operator+ 尽量少用,因为传值返回,导致深拷贝效率低
operator>> (重点) 输入运算符重载
operator<< (重点) 输出运算符重载
getline (重点) 获取一行字符串
relational operators (重点) relational operators (重点)
  • operator+

连接字符串,返回一个新构造的string对象,其值由lhs中的字符和rhs中的字符拼接而成。

  • getline (重点)

【剖析STL】String

getline(istream& is, string& str, char delim);

  • 🔥这个形式的函数从输入流is中读取一行文本,并将其存储在str字符串中,直到遇到指定的分隔符delim为止。如果没有指定分隔符,则默认为换行符。读取的分隔符不包括在存储的字符串中。
int main()
{
	string line;
	char delim = ':';
	cout << "Enter a line with as delimiter :" << endl;
	getline(cin, line, delim);
	cout << "You entered:" << line << endl;
	return 0;
}

【剖析STL】String

getline(istream& is, string& str);

  • 🔥这个形式的函数从输入流is中读取一行文本,并将其存储在str字符串中,直到遇到换行符为止。读取的换行符不包括在存储的字符串中。

  • operator>> (重点)

【剖析STL】String

从流中提取字符串,从输入流中提取一个字符串,将该序列存储在str中,str被覆盖(之前的str值被替换)。

该函数重载运算符>>,使其行为与istream::operator>>中描述的一样,适用于c-string对象。

提取出的每个字符都会像调用push_back成员一样被添加到字符串中。

请注意,istream提取操作使用空格作为分隔符。因此,这个操作只会从流中提取可以认为是单词的内容。要提取整行文本,请参阅全局函数getline的字符串重载。

  • operator<< (重点)

【剖析STL】String

向流中插入字符串,将符合str的值的字符序列插入到os中。

  • relational operators (重点)

这个后面写模拟实现的时候,会详细讲解

【剖析STL】String

2.4String非常用接口说明

  • insert

在pos(或p)指定的字符之前插入额外的字符:

  • 🔥intsert不会将\0插入进去 的,string不推荐经常使用insert,能少用就少用

【剖析STL】String

int main()
{
	string s1("world");
	s1.insert(0, "hello");
	cout << s1 << endl;

	s1.insert(5, " ");
	cout << s1 << endl;
	return 0;
}
  • erase

从字符串中删除字符,删除字符串的一部分,减少其长度:

【剖析STL】String

  • 第一种:擦除字符串值中从字符位置pos开始并跨越len字符的部分(如果内容太短或len为string::npos,则擦除直到字符串末尾)。注意,默认实参会擦除字符串中的所有字符(类似于成员函数clear)。
  • 第二种:擦除指向p的字符。
  • 第三种:擦除[first,last)范围内的字符序列。
string s2("hello world");
	s2.erase(5, 1);
	cout << s2 << endl;

当删除的字符的个数超过了字符的个数会怎么样?

【剖析STL】String

  • replace

【剖析STL】String

int main()
{
	string s1("world");
	s1.insert(0, "hello");
	cout << s1 << endl;

	s1.insert(5, " ");
	cout << s1 << endl;
	return 0;
}

【剖析STL】String文章来源地址https://www.toymoban.com/news/detail-440093.html

到了这里,关于【剖析STL】String的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STL】手撕 string类

    目录 1,string类框架 2,string(构造) 3,~string(析构) 4,swap(交换) 5,string(拷贝构造) 1,常规法 2,简便法 6,size (字符长度) 7,c_str(返回字符形式的指针) 8,iterator(迭代器) 9,operator=(赋值) 1,常规写法 2,简便法 10,operator[](取值) 11,reserve(空间容量

    2024年02月04日
    浏览(41)
  • 【STL】string类 (下)

    目录 1,insert 2,erase 3,find 4,replace 5,rfind 6,substr 7,find_first_of 8,find_first_not_of 9,find_last_of 10,operator+ 11,getline 在 pos 位置之前插入字符串 擦除范围字符串 从 pos 位置开始,用 n 个字符替换; 上述可以看到,第一个替换从下标 0 开始用两个字符也就是 ” he “ 替换 “

    2024年02月05日
    浏览(69)
  • 【c++】STL--string

            最开始我们学习c语言的时候,我们发现刷题或者写代码都是比较麻烦的,如果说用c语言造一辆车,那么我需要用c语言先把轮子造好--各个零件,当我们造好之后再组装。那么c++则是造好了轮子,只需要我们组装就好了。这里的的STL里有各个组件,我只要熟悉的掌握

    2024年02月03日
    浏览(49)
  • 【STL】优先级队列剖析及模拟实现

    ✍ 作者 : 阿润菜菜 📖 专栏 : C++ 优先队列是一种 容器适配器 ,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的(默认大堆)。优先级队列的内部实现通常是用 堆 来维护元素的优先级,使得每次出队的元素都是当前队列中优先级最高的元素。 优先

    2023年04月22日
    浏览(43)
  • STL常用容器—string容器

    本质: string是C++风格的字符串,而string本质上是一个类 string和char * 区别: char * 是一个指针 string是一个类,类内部封装了char *,管理这个字符串,是一个char *型的容器。 特点: string 类内部封装了很多成员属性和方法 string管理char*所分配的内存,不用担心复制越界和取值越

    2024年01月16日
    浏览(39)
  • C++ STL string类

    目录 一.为什么学习string类 (1) C语言中的字符串 (2)标准库里面的string类 二. string类的常用接口说明 (1)string类对象的常见构造 (2)string类对象的容量操作 1.size(),length(). 2. capacity() 3.empty()  4.clear()  5.reserve()  6.resize() (3)string类对象的访问及遍历操作  1.operator[ pos

    2024年02月13日
    浏览(35)
  • <C++_STL> string

    C语言中, 字符串 是以 \\\'\\0\\\' 结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会 越界访问 。 1.string类是表示字符序列的类 2.标准的st

    2024年02月03日
    浏览(40)
  • STL-string-2

    Iterators   Capacity Resize string 将字符串的大小调整为n个字符的长度。 如果n小于当前字符串长度,则当前值将缩短为其第一个n字符,删除第n个字符之后的字符。 如果n大于当前字符串长度,则通过在末尾插入所需数量的字符以达到n的大小来扩展当前内容。如果指定了c,则将新

    2024年02月09日
    浏览(47)
  • STL-string-1

    Convert string to integer 解析str,将其内容解释为指定基数的整数,该整数作为int值返回。 如果idx不是空指针,函数还会将idx的值设置为str中数字后面第一个字符的位置。 函数使用strtol(或wcstol)来执行转换(有关过程的更多详细信息,请参阅strtol)。 Convert string to long int 解析

    2024年02月07日
    浏览(38)
  • 【C++】STL——vector 深度剖析 及 模拟实现

    这篇文章我们来学习一下STL里面的vector,它属于STL中容器的一员,我们先来学习一下它的使用,然后,我们也会对vector进行一个深度的剖析和模拟实现。 1.1 vector的介绍 vector的文档介绍 vector 是表示大小可以更改的数组的序列容器: 其实大家可以认为 vector就是我们之前数据结

    2024年02月05日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包