STL简介 + string【上】
一 . STL简介
1.1 什么是STL
STL(standard template libaray - 标准模板库) : 是C++标准库的重要组成部分 , 不仅是一个可复用的组件库 , 而且是一个包罗 数据结构 与 算法 的软件框架 。
注意 : 是标准库的一部分 !C++标准库还包括其他的库 ,比方如下:
1.2 STL的版本
- 原始版本
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许
任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原
始版本一样做开源使用。 HP 版本--所有STL实现版本的始祖。
做一个小的知识扩展:(比较出名的闭源和开源有)
闭源 : windows mac os , Oracle
开源 : linux git
- 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要阅读部分源代码,主要参考的就是这个版本。
1.3 STL的六大组件

1.4 STL的重要性
网上有句话说:“不懂STL,不要说你会C++”。STL是C++中的优秀作品,有了它的陪伴,许多底层 的数据结构以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞的快速开发。
1.5 如何学习STL
学习STL的三个境界:能用,明理,能扩展

二 . 标准库中的string 类
注 :这里会比较详细的介绍string 类 , 以及文档怎样详细阅读 。记住 , 死记硬背是不可取的 , 理解并且熟悉使用才是根本 , 不懂的时候 , 可以在文档里查找。
2.1 string 类(了解)
string 类的文档介绍 :string - C++ Reference
在使用string 类时 , 必须包含 #include 头文件以及 using namespace std;

2.2 auto 和 范围 for
这里补充两个C++的小语法 , 方便我们后续的学习 。
auto 关键字

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

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;//auto -- 自动推导类型
int func1()
{return 1;
}
int main()
{int a = 10;auto b = a;auto c = 'a';auto d = func1();//编译报错: error C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项//auto e;int x = 10;auto y = &x;//右边必须是指针auto* z = &x;auto& k = x;auto aa = 1, bb = 2;//编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型//auto cc = 1,dd = 2.0;//编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型//auto a[] = { 1,2,3 };return 0;
}
一般内置类型直接写就好了,没必要转化为 auto , 那么时候使用auto?
替代长类型

#include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{std::map<std::string, std::string> dict = { { "apple", "苹果" },{ "orange","橙子" }, {"pear","梨"} };// auto的用武之地//std::map<std::string, std::string>::iterator it = dict.begin();auto it = dict.begin();while (it != dict.end()){cout << it->first << ":" << it->second << endl;++it;}return 0;
}
auto 做返回值,层层推导的时候 很不方便 ,要么就把注释写清楚 ,提高代码的可读性 ,下面代码如果想要知道 ret 是什么类型的 ,要经过 fun3 -> func2 ->func1 , 层层推导出 int , 如果代码很长 , 就不方便阅读代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;//auto 做返回类型层层推导的时候,很不方便...
int func1()
{return 1;
}
auto func2()
{return func1();
}
auto func3()
{return func2();
}
int main()
{auto ret = func3();return 0;
}
范围 for (语法糖)
在学习中 , 会听过类似语法糖的词汇 , 就是某个语法 用起来很 “甜” , 很方便 , 玩起来很开心

- 对于一个有范围的集合而言 , 由程序员来说明循环的范围是多余的 , 有时候还会容易错误 , 因此 C++11中引入了基于范围的 for 循环 。 for循环后的括号由冒号 " : " 分为两部分 : 第一部分是范围内用于迭代的变量 , 第二个部分则标识被迭代的范围 , 自动迭代 , 自动取数据 , 自动判断结束 。
- 范围 for 可以用作用到 数组 和 容器对象 上进行遍历
- 范围 for 的底层很简单 , 容器遍历实际就是替换为迭代器 , 这个从汇编层也可以看到。

#include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{int array[] = { 1, 2, 3, 4, 5 };// C++98的遍历for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){array[i] *= 2;}for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){cout << array[i] << " ";}cout << endl;//范围for//语法糖:自动++,自动判断,自动执行for (auto & e : array){e *= 2;}for (auto e : array){cout << e << " ";}cout << endl;return 0;
}

2.3 string 类的常用接口说明
通过文档 , 我们发现string 没在containers , 这是由于历史的原因导致的 , string 出现比STL早 , 但是string 的功能角度看 , 可以把string 归纳到 containers


我们点开string 来看 , 发现string 实际上是basic_string 类被 typedef , 这里重点学string , 因为接口的高度相似,并且用的最多的是string , 因为string 方便存储在utf8

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;int main()
{cout << sizeof(char) << endl;cout << sizeof(wchar_t) << endl;cout << sizeof(char16_t) << endl;cout << sizeof(char32_t) << endl;return 0;
}

1 . string 类对象的常见构造
string::string - C++ Reference


析构的话 , 底层会自动释放,自动调用

string 的构造有很多 , 需要记住是无参构造,有参构造,拷贝构造,其他的了解即可,使用时忘记随时查阅文档 , 无需刻意记忆 , 多练
2 . string类对象的容量操作

注意 :
1 . size() 与 length() : 方法底层实现原理完全相同 , 引入size()的原因 是为了与其他容器的接口保持一致 , 一般情况下基本都是用size()。
2 . max_size() : 没什么实际意义 ,因为实际中开不了这么大的空间 。
3 . clear() : 只是将string中有效字符清空 , 不改变底层空间大小
4 . capacity() : 返回容量 , 不包含'/0';
5 . shrink_to_fit :

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

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include <string>void Test_String1()
{string s("hello world!");cout << s.size() << endl;cout << s.capacity() << endl;//测试reserve是否会改变string中有效元素个数s.reserve(100);cout << s.size() << endl;cout << s.capacity() << endl;//测试reserve参数小于string的底层空间大小时,是否会将空间缩小s.reserve(5);cout << s.size() << endl;cout << s.capacity() << endl;//利用reserve提高插入数据的效率,避免增容带来的开销
}
int main()
{Test_String1();return 0;
}
7 . resize(size_t n ) 与 resize(size n , char c) : 都是将字符串有效字符个数改变到 n 个 , 不同的是当字符个数增多时 , resize(n) 用 0 来填充多出的元素空间 , resize(size_t n , char c)用字符 c 来填充多出的元素空间 。 注意resize在改变元素个数时 , 如果时将元素个数增多 , 可能会改变底层容量的大小 , 如果将元素个数减少 , 底层空间总大小不变 。

void Test_String2()
{string s("hello world!");cout << "size:"<< s.size() << endl;cout << "capacity:"<<s.capacity() << endl;cout << "s:" << s << endl;cout << endl;//将s中的字符串清空,注意清空时只是将size清0,不改变底层空间s.clear();cout << "size:" << s.size() << endl;cout << "capacity:" << s.capacity() << endl;cout << "s:" << s << endl;cout << endl;//将s中有效字符个数增加到10个,多出位置用'a'进行填充s.resize(10, 'a');cout << "size:" << s.size() << endl;cout << "capacity:" << s.capacity() << endl;cout << "s:" << s << endl;cout << endl;//将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行补充s.resize(15);cout << "size:" << s.size() << endl;cout << "capacity:" << s.capacity() << endl;cout << "s:" << s << endl;cout << endl;//将s中有效字符个数缩小到5个s.resize(5);cout << "size:" << s.size() << endl;cout << "capacity:" << s.capacity() << endl;cout << "s:" << s << endl;cout << endl;
}

3. string类对象的访问 及 遍历 操作

1 )string 类访问对象 : 使用 [] , 或者at

不同点就是 访问失败 的时候返回形式不同 ,at 访问失败会抛异常(程序还会继续跑,比较温和的方式) , [] 访问失败 , 断言(直接结束程序运行 , 比较暴力的方式)
2 ) 遍历string 对象的方式 :
1 . 下标 + [ ] : 运算符重载operaror[]
2 . 迭代器
3 . 范围 for
先来看 下标 + [] 的遍历方式 :
#include <string>
int main()
{//无参的构造string st1;//带参的构造string st2("Hello World!");//拷贝构造string st3(st2);string st4(st2, 6, 1000);cout << st1 << endl;cout << st2 << endl;cout << st3 << endl;cout << st4 << endl;//1.下标+[] for (size_t i = 0; i < st2.size(); i++){st2[i] += 1;}for (size_t i = 0; i < st2.size(); i++){cout << st2[i] << " ";}cout << endl;return 0;
}
实际上是重载了[] 运算符 , 能够使string 能像数组一样被访问 , 底层的operator[] 如下 :
namespace bit
{class string{public:char& operator[](size_t pos){assert(pos < _size);return _str[pos];}private:char* _str;size_t _size;size_t _capacity;};
}
这里我们就能深刻体会到 引用&作为返回值 的意义 :

再来看 迭代器遍历 :
//2 .迭代器// [ )string::iterator it = st2.begin();while (it != st2.end()){cout << *it << " ";++it;}cout << endl;

思考 : 为什么有了 下标 + [] 的遍历方式还需要有 迭代器 呢 ? 前者明明用到更顺。
因为下标 + [] 限制底层必须是数组,像链表就被限制了 , 但迭代器是通用的!
倒着遍历 : 反向迭代器(链表不一定有反向迭代器)
string::reverse_iterator rit = st2.rbegin();while (rit != st2.rend()){cout << *rit << endl;++rit;}cout << endl;

迭代器有四种 :

范围for 遍历 :
//范围for -- 底层是迭代器for (auto ch : st2){cout << ch << " ";}cout << endl;
编译器编译 范围for 的时候 , 替换为迭代器 。
所以从上层看有三种遍历方式:下标+[] , 迭代器,返回for , 底层就只有两种遍方式 : 下标+[] 和迭代器!
4. string类对象的修改操作

1 ) push_back() / append() / opeartor+=() 都是在 字符串后追加 (尾插)
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;#include <string>
void Test_string1()
{string s1;cout << s1.max_size() << endl;
}
void Test_string2()
{string s1;string s2("hello world");cout << s2.size() << endl;cout << s2.capacity() << endl;
}
void Test_string3()
{string s1;s1.push_back('x');s1.push_back('x');s1.push_back('x');s1.append("yyy");string s2("hello world");s1.append(s2.begin(), s2.end());//迭代区间可以取字符串的一部分s1.append(s2.begin() + 6, s2.end());cout << s1 << endl;//实际上,push_back与append不常用,+=最常用//类似c的 strcat , 1)从字符串开始找到'\0'后再追加//2)不会对原始空间扩容,追加会比较容易越界s1 += ' ';s1 += "zzz";s1 += s2;cout << s1 << endl;}int main()
{//Test_string1();//Test_string2();Test_string3();return 0;
}
2) insert 从某个位置开始插入 : 谨慎使用,头插数据时候 , 后面的数据需要全部往后挪

void Test_String3()
{string s("hello world!");s.insert(0, "xxx,");cout << "s:" << s << endl;s.insert(0, 1, 'a');cout << "s:" << s << endl;}
注意 :
1 . 在string 尾部追加字符时 , s.push_back(c) / s.append(1,c) /s+='c‘三种的实现方式差不多,一般情况下string类的+=操作用的比较多 , +=操作不仅可以连接单个字符 , 还可以连接字符串 。
2 . 对string 操作时 , 如果能够预估到放多少个字符 , 可以先通过 reserve 把空间预留好 。
3 ) erase: 删除数据

void Test_String4()
{string s("hello world!");//从第0个位置,删除一个字符s.erase(0, 1);cout << "s:" << s << endl;//头删一个数据s.erase(s.begin());cout << "s:" << s << endl;//不传参数时,默认从头开始,删完s.erase();cout << "s:" << s << endl;
}
5. string类非成员函数

相关文章:
STL简介 + string【上】
一 . STL简介 1.1 什么是STL STL(standard template libaray - 标准模板库) : 是C标准库的重要组成部分 , 不仅是一个可复用的组件库 , 而且是一个包罗 数据结构 与 算法 的软件框架 。 注意 : 是标准库的一部分 ÿ…...
【Bluedroid】A2DP Sink播放流程源码分析(二)
接上一篇继续分析:【Bluedroid】A2DP Sink播放流程源码分析(一)_安卓a2dp sink播放流程-CSDN博客 AVDTP接收端(Sink)流事件处理 bta_av_sink_data_cback 是 Bluedroid 中 A2DP Sink 角色的 AVDTP 数据回调函数,负责处理接收端的音频数据事件,将底层接收到的音频数据传递…...
redis利用备忘录
fofa: icon_hash"864611937" 防护: redis的安全设置:设置完毕,需要重加载配置文件启动redis 1.绑定内网ip地址进行访问 2. requirepass设置redis密码 3.保护模式开启protected-mode开启(默认开启) 4.最好把…...
SAP系统中MD01与MD02区别
知识点普及-MD01与MD02区别 1、从日常业务中,我们都容易知道MD01是运行全部物料,MD02是运行单个物料 2、在做配置测试中,也出现过MD02可以跑出物料,但是MD01跑不出的情况。 3、MD01与MD02的差异: 3.1、只要在物料主数…...
企业官网nodejs mySQL数据库安装及使用
以下是企业官网的MySQL数据库设计、本地安装指南,以及基于Node.js的增删改查(CRUD)实现方案: 一、MySQL数据库设计(企业官网基础表) 1. 核心表结构 -- 1. 用户表(管理员) CREATE T…...
Spring Boot自动配置原理深度解析:从条件注解到spring.factories
大家好!今天我们来深入探讨Spring Boot最神奇的特性之一——自动配置(Auto-configuration)。这个功能让Spring Boot如此受欢迎,因为它大大简化了我们的开发工作。让我们一起来揭开它的神秘面纱吧!👀 🌟 什么是自动配置…...
ubuntu学习day3
3 编译与调试 3.1 gcc/g编译器 当我们进行编译的时候,要使用一系列的工具,我们称之为工具链。SDK就是编译工具链的简写,我们所使用的是gcc系列编译工具链。使用-v参数来查看gcc的版本,从而确定某些语法特性是否可用,…...
C++数据结构与二叉树详解
前言: 在C编程的世界里,数据结构是构建高效程序的基石,而二叉树则是其中最优雅且应用广泛的数据结构之一。本文将带你深入理解二叉树的本质、实现与应用,助你在算法设计中游刃有余。 一、二叉树的基本概念 1. 什么是二叉树 二叉树…...
论文阅读:2023 arxiv Safe RLHF: Safe Reinforcement Learning from Human Feedback
总目录 大模型安全相关研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 Safe RLHF: Safe Reinforcement Learning from Human Feedback https://arxiv.org/pdf/2310.12773 https://github.com/PKU-Alignment/safe-rlhf 速览 研究动机ÿ…...
C++11中的std::condition_variable
一、什么是条件变量? std::condition_variable 是C11标准库中提供的线程同步工具,用于在多线程环境中实现“等待-通知”机制。它的核心作用是让线程能够高效地等待某个条件成立,避免“忙等待”对CPU资源的浪费。 条件变量必须与std::mutex配…...
6.8.最小生成树
一.复习: 1.生成树: 对于一个连通的无向图,假设图中有n个顶点,如果能找到一个符合以下要求的子图: 子图中包含图中所有的顶点,同时各个顶点保持连通, 而且子图的边的数量只有n-1条࿰…...
QT中栅格模式探索
1、Qt中选择了栅格模式,如下图所示: 2、在进行整个大的UI界面布局时,需了解每个控件所需要选择的属性sizePolicy。 sizePolicy包含如下几种选择: 3、举个例子:此时整个UI界面,我采用了栅格模式…...
SLAM | 激光SLAM中的退化问题
在激光SLAM中,判断退化环境的核心是通过数学建模分析环境特征对位姿估计的约束能力。除了LOAM中提出的退化因子D外,还存在多种基于表达式和阈值设定的方法。以下是几种典型方法及其实现原理: 1. 协方差矩阵特征值分析 原理:通过分析点云协方差矩阵的特征值分布,判断环境中…...
C++入门基础:命名空间,缺省参数,函数重载,输入输出
命名空间: C语言是基于C语言的,融入了面向对象编程思想,有了很多有用的库,所以接下来我们将学习C如何优化C语言的不足的。 在C/C语言实践中,在全局作用域中变量,函数,类会有很多,这…...
tomcat 的安装与启动
文章目录 tomcat 服务器安装启动本地Tomcat服务器 tomcat 服务器安装 https://tomcat.apache.org/下载 Tomcat 10.0.X 启动本地Tomcat服务器 进入 Tomcat 的 bin...
C 语言中经典的数据结构
在 C 语言中,经典的数据结构通常包括以下几种,每种都有其特定的应用场景和实现方式: 1. 数组(Array) 定义:连续内存空间存储相同类型的数据。 特点:随机访问快(O(1))&am…...
算法-堆+单调栈
堆 首先堆在我们的Java中我们的是一个优先队列类 PriorityQueue 然后我们要弄最大堆和最小堆 最大堆: PriorityQueue<Integer> pq new PriorityQueue<Integer>((a, b) -> b - a); 最小堆: PriorityQueue<Integer> pq new P…...
物联网平台管理系统
物联网平台管理系统概述 物联网平台管理系统是物联网架构中的核心枢纽,承担着承上启下的关键作用。它向下连接各类物联网设备,实现设备的接入、管理与控制;向上为应用开发提供统一的数据接口和共性模块工具,支撑起各种丰富多彩的…...
STM32CubeMX-H7-15-SPI通信协议读写W25Q64
前言 SPI(Serial Peripheral Interface)通信协议是一种高速、全双工、同步的串行通信协议 本篇文章就使用W25Q64模块来学习SPI,包括软件SPI代码的编写,硬件SPI,中断SPI和DMASPI SPI的应用场景和模块 !这里是抄AI的&a…...
【软考】论devops在企业信息系统开发中的应用
摘要: 随着互联网的不断发展,各行各业都在建设自己的企业信息系统,而随着业务的不断升级和复杂化,系统的更新迭代速度越来越快,系统也越来越复杂。对于信息系统开发者,架构师,管理者,…...
生物化学笔记:医学免疫学原理22 肿瘤及肿瘤治疗
肿瘤及肿瘤治疗 免疫疗法 CAR-T细胞介绍...
JVM考古现场(二十二):降维打击·用二向箔优化内存模型
"警报!三维堆内存正在经历二维化坍缩!" 我腰间的玄铁令突然震动,在蜀山剑派的量子剑阵中投射出诡异的曼德博分形——这是三体文明发动降维打击的铁证! 楔子:二向箔奇点降临 昆仑镜监控日志: // …...
第三阶段面试题
Nginx nginx常用模块以及其功能 proxy模块,进行代理功能 ssl模块,进行HTTPS协议的使用 gzip模块,进行传输数据的压缩 upstream模块,进行反向代理时使用 static模块,静态资源进行访问的模块 cache模块࿰…...
操作系统-PV
🧠 背景:为什么会有 PV? 类比:内存(生产者) 和 CPU(消费者) 内存 / IO / 磁盘 / 网络下载 → 不断“生产数据” 例如:读取文件、下载视频、从数据库加载信息 CPU → 负…...
nuxt3路由切换页面出不来,刷新可以
nuxt3遇到一个奇怪的现象: 不管是router.push()跳转还是navigateTo()跳转,浏览器url变了,但是页面是空白的,没加载出来,刷新之后页面正常。 解决方案: <template>下的所有内容必须套在一个div里面...
Spring Boot配置文件优先级全解析:如何优雅覆盖默认配置?
📚 一、为什么需要了解配置文件优先级? 想象一下,你正在玩一个游戏🎮,游戏里有默认设置,但你可以通过不同的方式修改这些设置: 游戏内置的默认设置(就像Spring Boot的默认配置&…...
医院数据中心智能化数据上报与调数机制设计
针对医院数据中心的智能化数据上报与调数机制设计,需兼顾数据安全性、效率性、合规性及智能化能力。以下为系统性设计方案,分为核心模块、技术架构和关键流程三部分: 一、核心模块设计 1. 数据上报模块 子模块功能描述多源接入层对接HIS/LIS/PACS/EMR等异构系统,支持API/E…...
Linux之基础命令
Linux作为开源操作系统的代表,以其高效、灵活和强大的命令行工具闻名。无论是系统管理、开发调试还是日常使用,掌握基础命令都是与Linux系统交互的必备技能。本文整理了20个最常用的Linux基础命令,帮助新手快速入门。 目录 目录与文件导航文…...
【MATLAB代码例程】AOA与TOA结合的高精度平面地位,适用于四个基站的情况,附完整的代码
本代码实现了一种基于到达角(AOA) 和到达时间(TOA) 的混合定位算法,适用于二维平面内移动或静止目标的定位。通过4个基站的协同测量,结合最小二乘法和几何解算,能够有效估计目标位置,并支持噪声模拟、误差分析和可视化输出。适用于室内定位、无人机导航、工业监测等场景…...
PC主板及CPU ID 信息、笔记本电脑唯一 MAC地址获取
🥇 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 🎉 声明: 作为全网 AI 领域 干货最多的博主之一,❤️ 不负光阴不负卿 ❤️ 文章目录 PC主板及CPU ID 信息物理 MAC地址获取win11 新电脑 wmic 安装❤️ 欢迎一起学AI…...


