C++STL库

学习方法:使用STL的三个境界:能用,明理,能扩展。

今天我们开启一个新主题:C++数据结构之STL库,我们将介绍STL库里常用库的用法与实现过程。

常用库

库名称

所需头文件

数据结构

string

#include<string>

vector

#include<vector>

动态数组

list

#include<list>

带头双向循环链表

queue

#include<queue>

队列

stack

#include<stack>

deque

#include<deque>

双端队列

priority_queue

#include<queue>

优先队列

string类

string类的介绍

注意:C++的string严格来说是一个类,是一个对象,不是一个类型。

1.字符串是表示字符序列的类;

2.标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。

3.string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。

4.string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(更多的模板信息请参考basic_string)。

5.注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

总结:

1.string是表示字符串的字符串类

2.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

3.string在底层实际是:basic_string模板类的别名,typedef basic_stringstring;

4.不能操作多字节或者变长字符的序列。

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


string类对象的常见构造

函数名称

功能说明

string() (重点)

构造空的string类对象,即空字符串

string(const char* s) (重点)

用C-string来构造string类对象

string(size_t n, char c)

string类对象中包含n个字符c

string(const string&s) (重点)

拷贝构造函数

举例:

#include <iostream> #include <string>  using namespace std;  int main() {     string s1;         // 构造空的string类对象s1     string s2("i 1ove");  // 用C格式字符串构造string类对象s2     string s3(9, 'u');     string s4(s2);   return 0; }​

容量方法

以下均为类公共成员函数

方法名称

用途

size(重点)

返回字符串有效字符长度

length

返回字符串有效字符长度

max_size

返回字符串支持的最大字符数

resize(重点)

将有效字符的个数改成n个,多出的空间用字符c填充

capacity(重点)

返回空间总大小

reserve

请求更改容量,为字符串预留空间

clear(重点)

清除字符串

empty(重点)

测试字符串是否为空

shrink_to_fit

请求字符串减小其容量以适应其大小

重点实例:

// size/clear/resize void Teststring1() {   // 注意:string类对象支持直接用cin和cout进行输入和输出   string s("hello, World!!!");   cout << s.size() << endl;   cout << s.length() << endl;   cout << s.capacity() << endl;   cout << s << endl;   // 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小   s.clear();   cout << s.size() << endl;   cout << s.capacity() << endl;   // 将s中有效字符个数增加到10个,多出位置用'a'进行填充   // “aaaaaaaaaa”   s.resize(10, 'a');   cout << s.size() << endl;   cout << s.capacity() << endl;   // 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充   // "aaaaaaaaaa\0\0\0\0\0"   // 注意此时s中有效字符个数已经增加到15个   s.resize(15);   cout << s.size() << endl;   cout << s.capacity() << endl;   cout << s << endl;   // 将s中有效字符个数缩小到5个   s.resize(5);   cout << s.size() << endl;   cout << s.capacity() << endl;   cout << s << endl; }  //==================================================================================== void Teststring2() {   string s;   // 测试reserve是否会改变string中有效元素个数   s.reserve(100);   cout << s.size() << endl;   cout << s.capacity() << endl;   // 测试reserve参数小于string的底层空间大小时,是否会将空间缩小   s.reserve(50);   cout << s.size() << endl;   cout << s.capacity() << endl; } // 利用reserve提高插入数据的效率,避免增容带来的开销 //==================================================================================== void TestPushBack() {   string s;   size_t sz = s.capacity();   cout << "making s grow:\n";   for (int i = 0; i < 100; ++i)   {     s.push_back('c');     if (sz != s.capacity())     {       sz = s.capacity();       cout << "capacity changed: " << sz << '\n';     }   } } void TestPushBackReserve() {   string s;   s.reserve(100);   size_t sz = s.capacity();   cout << "making s grow:\n";   for (int i = 0; i < 100; ++i)   {     s.push_back('c');     if (sz != s.capacity())     {       sz = s.capacity();       cout << "capacity changed: " << sz << '\n';     }   } }

注意:

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

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

3.resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

4.reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

访问及遍历操作

函数名称

功能说明

operator[] (重点)

返回pos位置的字符,const string类对象调用

begin+ end

begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭 代器

rbegin + rend

begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭 代器

范围for

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

实例代码:

void Teststring(){       string s1("hello World");       const string s2("Hello World");       cout << s1 << " " << s2 << endl;       cout << s1[0] << " " << s2[0] << endl;       s1[0] = 'H';       cout << s1 << endl;       // s2[0] = 'h'; 代码编译失败,因为const类型对象不能修改}void Teststring(){       string s("hello World");       // 3种遍历方式:       // 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,       // 另外以下三种方式对于string而言,第一种使用最多       // 1. for+operator[]       for (size_t i = 0; i < s.size(); ++i)       {              cout << s[i] << endl;       }       // 2.迭代器       string::iterator it = s.begin();       while (it != s.end())       {              cout << *it << endl;              ++it;       }       string::reverse_iterator rit = s.rbegin();       while (rit != s.rend())       {              cout << *rit << endl;       }       // 3.范围for       for (auto ch : s)       {              cout << ch << endl;       }}

类对象的修改操作

函数名称

功能说明

push_back

在字符串后尾插字符c

append

在字符串后追加一个字符串

operator+= (重点)

在字符串后追加字符串str

c_str(重点)

返回C格式字符串

find + npos(重点)

从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置

rfind

从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置

substr

在str中从pos位置开始,截取n个字符,然后将其返回

void Teststring(){       string str;       str.push_back(' '); // 在str后插入空格       str.append("I"); // 在str后追加一个字符"I"       str += 'lov'; // 在str后追加一个字符'1ov'       str += "it"; // 在str后追加一个字符串"it"       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;       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;       // 删除url的协议前缀       pos = url.find("://");           url.erase(0, pos + 3);       cout << url << endl;}

注意:

1.在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

2.对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好

类非成员函数

函数

功能说明

operator+

尽量少用,因为传值返回,导致深拷贝效率低

operator>> (重点)

输入运算符重载

operator<< (重点)

输出运算符重载

getline (重点)

获取一行字符串

relational operators (重点)

大小比较

string类的模拟实现

经典的string类问题

上面已经对string类进行了简单的介绍,只要能够正常使用即可。在面试中,面试官总喜欢让模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。观察以下代码,判断该string类的实现是否有问题?

class string{public:       /*string()       :_str(new char[1])       {*_str = '\0';}       */           //string(const char* str = "\0") 错误示范       //string(const char* str = nullptr) 错误示范       string(const char* str = "")       {              // 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下              if (nullptr == str)              {                     assert(false);                     return;              }              _str = new char[strlen(str) + 1];              strcpy(_str, str);       }           ~string()       {              if (_str)              {                     delete[] _str;                     _str = nullptr;              }       }private:       char* _str;};// 测试void Teststring(){       string s1("hello bit!!!");              // string不明确       string s2(s1);                                    // string不明确}

上述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷贝。

深拷贝

深拷贝:如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

写时拷贝(了解)

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。

引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

现代写法的string

本处最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。​具体完整的源码欢迎关注微信公众号“01编程小屋”,后台回复“C++String”获取完整源代码哦

class string{public:       string(const char* str = "")       {              if (nullptr == str)                     str = "";              _str = new char[strlen(str) + 1];              strcpy(_str, str);       }           string(const string& s)              : _str(nullptr)       {              string strTmp(s._str);              swap(_str, strTmp._str);       }           string& operator=(string s)       {              swap(_str, s._str);              return *this;       }         ~string()       {              if (_str)              {                     delete[] _str;                     _str = nullptr;              }       }private:       char* _str;};

后续我们还会继续更新C++STL库的用法详解与原理,如果你喜欢我们的文章别忘了关注我们的公众号​“01编程小屋”哦!后续我们都会在上面更新最新的文章,关注小屋,学习编程不迷路。你的​支持就是我们坚持做下去的动力!

C++STL库:String介绍相关推荐

  1. C++ STL库 string类型常见操作

    #include <iostream> using namespace std; int main() {/* 初始化 1 个 字符串(默认为空串, 即"") */st ...

  2. STL库:string

    STL库:string 文章目录 STL库:string 1.STL库对于string类的介绍 2.string常用接口的掌握 2.1 string的构造接口 2.2 string的容量操作接口 2. ...

  3. STL库中string类内存布局的探究

    在STL中有着一个类就是string类,他的内存布局和存储机制究竟是怎么样的呢? 这就是建立好的string 可以看出,图中用黄色框框标注的部分就是主要区域 我们用来给string对象进行初始化的字符 ...

  4. C++11 中STL库中新增内容

    C++ 11一个比较显著的变化是以前boost库中的一些函数被正式标准化合入到STL中了,本文就简单的介绍一下. 引用包装器(Reference Wrapper) 当模板函数参数为泛型类型的时候,无法 ...

  5. STL库:vector

    STL库:vector 文章目录 STL库:vector 1.STL库对vector的官方介绍 2.vecotr的常用接口 2.1 vector的构造函数 2.2 vector的迭代器与遍历操作 2. ...

  6. STL库:map和set

    STL库:map和set 文章目录 STL库:map和set 1.STL库中set的官方介绍 2.set的常用接口 3.set的总结 4.STL库中multiset的官方介绍 5.STL库中map的官 ...

  7. Qt框架与STL库之间的巅峰对决:差异、优缺点及适用场景

    Qt框架与STL库之间的巅峰对决:差异.优缺点及适用场景 引言 对比的重要性 Qt框架与STL库简介 博客内容概览 Qt框架基础 Qt框架的特点与组成 Qt的信号槽机制 Qt容器类简介 数据结构的对比 ...

  8. STL之string类:知其然,需知其所以然

    目录 前言 一,构造及初始化 1.1constuct类函数 1.2构造函数及其模拟实现 1.3拷贝构造及其模拟实现 1.4赋值操作符 1.5string类的swap接口 二,迭代器 2.1初识迭代器即 ...

  9. STL简介string的使用及其模拟实现

    文章目录 一.STL简介 1.什么是STL 2.STL的版本 3.STL的六大组件 4.STL的重要性 5.如何学习STL 二.标准库中的string类 1.string类 2.string类的常用接 ...

最新文章

  1. java中list排序
  2. java课堂作业(一)
  3. 阻塞队列-BlockningQueue
  4. [机器学习-概念] 什么是欧式距离、标准化欧式距离、马氏距离、余弦距离
  5. 【SSO-CAS】sso 之 cas 实现的几个问题
  6. 不要轻易在数据库(尤其是线上数据库)执行,update、delete数据 !!!
  7. P-Called-Party-ID 头域的应用说明
  8. java自动化开发_五大Java自动化测试框架
  9. Android11.0系统去掉桌面谷歌搜索栏
  10. 带通滤波器是什么,它的原理是什么
  11. Ubuntu 下图像标注工具 labelImg 的安装及使用
  12. 2020年ICPC辽宁省赛- 最长回文串(Java)
  13. MEDA: Meta-Learning with Data Augmentation for Few-Shot Text Classification
  14. 物联网系列之WIFI模块ESP8266一介绍
  15. 我也写了部lt;西游记gt;
  16. 锁相环(PLL)基本结构及相关基本知识
  17. 收入--支出=储蓄?
  18. Linux运维与架构工程实践
  19. 高中数学如何学好,必修一函数的单调性与最值(习题)
  20. 微信开发一服务器地址(URL)、令牌(Token)配置

热门文章

  1. 【无标题】60秒倒计时
  2. 深入源码,CompletableFuture 简单与链式的区别?
  3. Android root环境下设置ro.debuggable = 1
  4. Android Studio 与工具下载地址(谷歌、百度云、AndroidDevTools均可下载)
  5. js本地刷新和局部刷新
  6. 汽车软件开发相关词汇
  7. 中国百货业重磅报告!新零售玩得好的已经尝到甜头了
  8. php h m s 转为秒,将m³/s换算为m³/h (立方米每秒换算为立方米每小时)
  9. 双11购物狂欢已经开始,店宝宝:火热的直播电商正待加码
  10. HObject,unsigned char的相互转换