C++ STL 学习之【string】
✨个人主页: Yohifo
🎉所属专栏: C++修行之路
🎊每篇一句: 图片来源
The key is to keep company only with people who uplift you, whose presence calls forth your best.
- 关键是只与那些提升你的人在一起,他们的存在唤起了你最好的一面。
文章目录
- 📘前言
- 📘正文
- 📖basic_string
- 📖编码理解
- 📖构造函数相关
- 🖋️无参(默认)构造函数
- 🖋️带参构造函数
- 📖容量操作相关
- 🖋️获取数据
- 🖋️扩容空间
- 🖋️调整长度
- 📖遍历字符相关
- 🖋️下标访问
- 🖋️迭代器
- 📖字符修改相关
- 🖋️尾插字符/字符串
- 🖋️任意位置插入字符/字符串
- 🖋️删除字符/字符串
- 🖋️查找字符/字符串位置
- 🖋️截取字符串
- 📖非成员函数
- 🖋️流操作
- 🖋️获取字符串
- 🖋️比较函数
- 📖相关试题
- 📘总结
📘前言
STL 是 C++ 的重要组成部分,由六大部分构成:伪函数、空间配置器、算法、容器、迭代器 和 配接器,其中各种各样的 容器 可以很好的辅助我们写程序,比如今天要介绍的 string,有了它之后,我们对字符串的操作就能变得行云流水

注意: string 诞生于 STL 之前,因此存在部分接口冗余的情况
📘正文
本文介绍的是 string 部分常用接口
📖basic_string
string 是 basic_string模板 的一份实例,因为字符串多种多样,所以 string 也有各种各样的版本
string常规字符串类,即每个字符占位1bytewstring宽字符串类,用来处理较长字符串,Winows下占位2byte,而 Linux下占位4byteu16string匹配UTF-16编码标准,指定字符占位2byte(C++11)u32string匹配UTF-32编码标准,规定字符占位4byte(C++11)
世界上有各种各样的语言,其字符长度大多不一样,因此需要使用不同的 string 来匹配输出自己国家的字符

📖编码理解
我们这里介绍的是 string 类,它匹配 UTF-8 标准,而此标准又兼容了 ASCII 码,因此比较常用
ASCII 是美国信息标准交换代码,仅仅通过 1byte 就能满足其字符需求

UTF-8 的特点是能根据不同范围的字符匹配使用不同的标准,因为ASCII 都是 0xxxxxxx 的形式,当识别到其他字符时,会匹配使用对应标准,比如当识别到汉字时,会使用 GBK 编码标准来进行输出(Windows)

后续随着万国码 Unicode 的诞生,提出了能适用更多语言的编码标准,即 UTF-16 和 UTF-32 ,而 basic_string 中的 u16string 和 u32string 这两个类就是用来匹配编码标准的
注: 这两个类是在 C++11 标准中制定的
我们的 string 其实就是 basic_string <char> 的别名

📖构造函数相关
现在正式进入 string 类的学习,先从默认成员函数—构造函数入手
注意: string 包含于 iostream 头文件中,并且还需要展开 std 命名空间
🖋️无参(默认)构造函数
#include<iostream>
using namespace std;int main()
{string s; //此时调用的是无参构造函数return 0;
}
调用无参构造函数时,默认将对象初始化为空串,即只包含 '\0' 的字符串

🖋️带参构造函数
我们也可以指定 string 对象中的内容
int main()
{string s("Hello String!"); //指定内容//string s = "Hello String!"; //下面这种写法也是完全可以的return 0;
}

string 也支持将对象构造为 n 个字符 c
int main()
{string s(10, 'w'); //构造10个w字符return 0;
}

最后再来看看 string 类的 拷贝构造 函数
int main()
{string s1("Hello");string s2(s1); //将 s1 的内容构造给 s2//string s2 = s1; //这种写法也是可以的return 0;
}

📖容量操作相关
我们可以把 string 类看作一个专门用来处理字符的顺序表,因为它有字符指针、容量、长度等信息,我们也可以进行手动扩容等操作
🖋️获取数据
获取 string 对象中指向字符串的指针 _str
C++兼容C,在某些场景下需要使用指向字符串的指针,因此 string 类中提供了这个接口
int main()
{string s("hello");cout << s.c_str() << endl; //获取对象s中的字符串指针return 0;
}

此时直接打印内容的原因是当指针指向对象为常量字符串时,编译器会直接打印内容
我们可以通过强转来观察函数 c_str()
cout << (void*)s.c_str() << endl; //此时指针非常量字符指针

通过函数 capapcity() 和 size() 获取当前对象的容量和大小
int main()
{string s(200, 'H'); //直接构造200个字符Hcout << "The string capacity is " << s.capacity() << endl;cout << "The string size is " << s.size() << endl;//cout << "The string size is " << s.length() << endl; //这种方式也能获取大小return 0;
}

length() 函数能起到和 size() 函数完全一样的效果, 那为什么会有两个函数呢?
string诞生于STL之前,当时的设计的获取大小函数为length()- 后来当
string并入STL后,委员会为了统一化,就在string类中添加了一个size()函数,因为其他容器中获取大小的函数都是size() - 为了确保向前兼容性,不能直接删除
length(),这里推荐使用size()
🖋️扩容空间
new 出来的空间不支持像 realloc 一样直接扩容,而是需要通过函数扩容
realloc大多数情况下都是异地扩容,即开辟-拷贝-销毁-更改指向- 而
reserve()函数实现的就是异地扩容
int main()
{string s(30, 'H'); //初始化大小为10cout << "The default capacity " << s.capacity() << endl;s.reserve(300); //扩容为300cout << "The expansion capacity " << s.capacity() << endl;return 0;
}

VS 中的容量都会稍微多一点
假若我们不手动扩容,string 也会像顺序表一样,识别到容量不够时,自动扩容
VS中 string 的扩容策略
- 默认给一个大小为
15的数组存储数据,当数组够用时,都是用的数组 - 当数组容量不够时,改用指针,先
2倍扩容至30,后续字符都是存在指针中 - 之后的扩容操作,都是以
1.5倍进行扩容 - 会多开辟一些空间
Linux中 string 的扩容策略
- 默认大小为
0的空间 - 当第一次扩容时,会先扩至
1 - 扩容时每次都是
2倍扩容法,比较清晰 - 不会多开空间
int main()
{string s;int capacity = s.capacity();cout << "The default capacity " << capacity << endl;int n = 0;while (n <= 100){//尾插字符s += 'a';if (capacity != s.capacity()){capacity = s.capacity();cout << "The new capacity " << capacity << endl;}n++;}return 0;
}

至于 Windows 中为何如此复杂?首先是 STL 版本不同,其次string 在实际使用中,都用不了太大的空间,因此 VS 就直接索性给了一个默认大小为 15 的数组,后续有需要再进行扩容
频繁扩容会导致内存碎片问题,VS在这里的处理方法是比较合理的
小技巧: 在使用 string 时,可以先提前计算好需要的空间,然后通过 reserve 直接提前扩好,避免因自动扩容而导致的内存碎片问题
🖋️调整长度
除了可以扩容外,我们还可以改变 size
int main()
{string s(50, 'W'); //当前的 size 为50cout << "The default size " << s.size() << endl;cout << "The default capacity " << s.capacity() << endl;cout << endl;s.resize(30); //改变 size 为30//s.resize(100, 'Z'); //还可以这样写,更改后50块空间为 Zcout << "The new size " << s.size() << endl;cout << "The new capacity " << s.capacity() << endl;return 0;
}

resize() 有两种情况:
- 调整后空间比原空间大,此时相当于扩容
reserve(),不过resize()还有一个初始化的功能,即将参数2设为指定字符,如果没有指定就默认为\0 - 调整后空间比原空间小,此时将
_size调整至目标空间,而 _capapcity 不变,此时我们也无法访问到_size之外的数据
resize() 并不会缩容,因为缩容的代价比较大,需要先开辟新空间,然后拷贝,释放原空间,才能完成缩容,因此 resize() 在处理时,若新空间比原空间小,是不会改变 _capaciy 的
📖遍历字符相关
字符串当然少不了遍历操作,主要有三种遍历方式:下标、at()、迭代器,因为 下标 和 at() 区别不大,所以可以一起介绍,而 迭代器 是一个很重要的东西,后续容器学习中都会出现它的影子
🖋️下标访问
首先来看看 下标访问,实现原理很简单:运算符重载 operator[]
int main()
{string s("chatGPT");size_t pos = 0; //下标while (pos < s.size()){//直接像数组一样通过下标访问字符cout << "The " << pos + 1 << " char is " << s[pos] << endl;pos++;}return 0;
}

当我们出现越界行为时,下标访问是直接通过 assert 报错的
下面再来看看 at()
cout << "The " << pos + 1 << " char is " << s.at(pos) << endl;
运行结果与 operator[] 一致,其实这两种方法的实现原理都一样,不过处理问题的方法不一样
当出现越界访问,at() 是抛出异常,而非直接断言报错
总的来说,at() 用的比较少,我们一般都是使用 operator[] 来进行下标的随机访问
🖋️迭代器
下面来看看迭代器 iterator 遍历字符串
int main()
{string s("chatGPT");//创建迭代器string::iterator it = s.begin(); //此时的it相当于指向第一个字符的指针//auto it = s.begin(); //可以利用 auto 自动识别类型while (it != s.end()){cout << *it;it++;}cout << endl;return 0;
}

注: begin() 获取第一个字符,end() 获取最后一个字符的下一个字符,即 '\0'
除了可以正向遍历外,我们还可以通过反向迭代器 reverse_iterator 进行反向遍历
int main()
{string s("chatGPT");//创建反向迭代器string::reverse_iterator rit = s.rbegin(); //此时的rit相当于指向最后一个字符的指针//auto it = s.begin();while (rit != s.rend()){cout << *rit;rit++;}cout << endl;return 0;
}

注: rbegin() 获取最后一个字符,rend() 获取第一个字符的前一个字符
迭代遍历区间都是左闭右开
除了上面两种普通迭代器外,还有两个 const 修饰的迭代器,用来遍历常量字符串
const_iterator正向遍历常量字符串const_reverse_iterator反向遍历常量字符串
注意:
- 迭代器名
const_iterator中的const并非是const操作符,而是与普通迭代器构成重载 - 迭代器不太适合遍历顺序表,适合用来遍历链表
- 所谓的
范围for其实就是在调用迭代器进行遍历
📖字符修改相关
现在来谈谈字符修改相关接口
🖋️尾插字符/字符串
尾插字符/字符串有三种方式:
push_back()尾插字符append()尾插字符/字符串operator+=尾插字符/字符串
先来看看 push_back()
int main()
{string s = "Hello ";//尾插字符s.push_back('X');cout << s << endl;return 0;
}

push_back() 就像是顺序表的尾插,一次只能插入一个字符
再来看看 append()
int main()
{string s = "Hello ";//尾插字符s.append(3, 'X'); //需要指定待插入的字符数s.append(" YYY"); //或者直接插入字符,都是可以的cout << s << endl;return 0;
}

append() 还有很多其他用法,感兴趣的可以去查看官方文档
最后再来看看 operator+= ,这个是使用频率最高的,因为比较方便
int main()
{string s = "Hello ";//尾插字符s += 'C'; //直接和字符拼接s += "SDN"; //和字符串拼接也是可以的cout << s << endl;return 0;
}

在日常使用中,对于字符串尾插这件事,我们通常都是使用 operator+=
🖋️任意位置插入字符/字符串
string 支持在任意位置插入字符/字符串
int main()
{string s("cccccc");cout << "Begin insert:" << s << endl;s.insert(2, 1, 'A'); //在第 n 个位置插入 m 个字符 cs.insert(4, "BBB"); //在第 n 个位置插入字符串cout << "After insert:" << s << endl;return 0;
}

insert() 的用法同样还有很多,可以自行查看官方文档
🖋️删除字符/字符串
有任意位置插入,当然就有任意位置删除 erase()
int main()
{string s("ABCDEFG");cout << "Begin erase:" << s << endl;//任意位置删除s.erase(3, 1); //从pos3开始,删除第1个字符cout << "After erase 1 char:" << s << endl;s.erase(2, 4); //从pos2开始,删除4个字符cout << "After erase 4 char:" << s << endl;s.erase(); //默认全删cout << "After erase all:" << s << endl;return 0;
}

注意: erase() 是一个全缺省参数,参数1为 0 ,表示默认从 pos0 开始,参数2为 npos,这是无符号整型中的 -1 ,为无符号整型最大值,意思就是如果不写参数2,默认就全删完了

来看看 npos

它的值是 4294967295,没有字符串长达 42亿 多,因此可以用来当作默认长度值
🖋️查找字符/字符串位置
string 类中提供了查找字符/字符串的函数 find()
int main()
{string s("My name is KiKi");//查找,返回的是目标字符/字符串第一次出现的下标cout << "Find 1 char pos: " << s.find('n') << endl; //找字符,默认从pos0开始cout << "Find str pos: " << s.find("KiKi", 5) << endl; //找字符串,从pos5开始cout << "Find not exist str pos: " << s.find("KaKa", 10) << endl; //假设没找到return 0;
}

可以看到,当目标不存在时,返回的就是 npos
find() 还有几种形式:
rfind()从后往前找find_first_of(str, pos = 0)从pos位置往后,找str中出现的任意字符find_last_of(str, pos = npos)从npos位置往前,找str中出现的任意字符find_first_not_of()反向查找find_last_not_of()反向查找
string 类的接口雀氏很多
🖋️截取字符串
我们可以截取字符串中的目标字符串 substr()
int main()
{string s("I am an iKun, love sing、jump、rap and basketball");//利用 find 和 substr 切割出 iKuncout << "The target is " << s.substr(s.find('i'), 4) << endl;return 0;
}

食不食油饼~
其实 substr() 通常用来截取网址中的域名
📖非成员函数
string类中还有很多定义在类外的非成员函数
🖋️流操作
我们可以直接对 string 对象使用流插入 operator<< 和流提取 operator>>
int main()
{string s;cin >> s;cout << s;return 0;
}

🖋️获取字符串
单纯的流插入是无法满足字符串插入需要的,因为字符串中往往都会包含 ' ',而 cin 会认为这是结束标志,进而不再读取字符,因此有专门的函数获取字符串 getline()
#include<string>int main()
{string s;getline(cin, s); //需要包含头文件 stringcout << s;return 0;
}

注意: 需要包含头文件 string
🖋️比较函数
string 类中存在一系列的大小比较函数(18个),光是判断相等就有3个,其实没必要设计这么多函数,这可能也是 string 饱受别人吐槽的原因之一,大佬陈浩也写过相关文章吐槽


原文出处:《STL中的string类怎么啦?》
📖相关试题
简单学完 string 类后,还是有很多试题值得我们去练习的,感兴趣的同学可以点击下面的链接直达题目仓库
string值得练习的题目
📘总结
以上就是本次关于 STL 之 string 的全部讲解了,string 类接口众多,但常用的也就那二三十个,其中大多数函数都有多个版本,如果还想了解更多关于 string 类细节的,可以阅读官方文档
如果你觉得本文写的还不错的话,可以留下一个小小的赞👍,你的支持是我分享的最大动力!
如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正

相关文章推荐 C/C++【内存管理】
===============
类和对象实操
类和对象实操之【日期类】
===============
类和对象系列
类和对象(下)
类和对象(中)
类和对象(上)
![]()
相关文章:
C++ STL 学习之【string】
✨个人主页: Yohifo 🎉所属专栏: C修行之路 🎊每篇一句: 图片来源 The key is to keep company only with people who uplift you, whose presence calls forth your best. 关键是只与那些提升你的人在一起,…...
使用开源 MaxKey 与 APISIX 网关保护你的 API
1. Apache APISIX介绍 Apache APISIX 是 Apache 软件基金会下的云原生 API 网关,它兼具动态、实时、高性能等特点,提供了负载均衡、动态上游、灰度发布(金丝雀发布)、服务熔断、身份认证、可观测性等丰富的流量管理功能。我们可以…...
Linux之Xshell工具使用
shell简介Xshell是一个远程工具,可以远程连接linux系统 ,SSH,远程管理 Xshell来远程访问Linux系统的终端 。shell的英文含义是“壳”;它是相对于内核来说的,因为它是建立在内核的基础上,面向于用户的一种表…...
【数据结构与算法】时间复杂度与空间复杂度
目录 一.前言 二.时间复杂度 1.概念 二.大O的渐进表示法 概念: 总结: 三.常见时间复杂度计算举例 例1 例2 例3 例4 例5.计算冒泡排序的时间复杂度 例6.二分算法的时间复杂度 例7.阶乘递归Fac的时间复杂度 例8.斐波那契递归的时间复杂度 …...
Nginx如何配置Http、Https、WS、WSS的方法步骤
这篇文章主要介绍了Nginx如何配置Http、Https、WS、WSS的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 写在前面 当今互联网领域,Nginx是使…...
【博客621】iptables -J动作总结
iptables -J动作总结 1、iptables常见动作 ACCEPTDROPREJECTLOGSNATDNATMASQUERADEREDIRECT 2、iptables常见动作用法 2-1、ACCEPT: 作用:用于接收匹配的流量,使得流量继续往后面的规则和链路去匹配 2-2、DROP 作用:用于丢弃匹…...
Chrome开发者工具:利用网络面板做性能分析
Chrome 开发者工具(简称 DevTools)是一组网页制作和调试的工具,内嵌于 Google Chrome 浏览器中。 Chrome 开发者工具有很多重要的面板,比如与性能相关的有网络面板、Performance 面板、内存面板等,与调试页面相关的有…...
SpringCloud系列(十三)[分布式搜索引擎篇] - ElasticSearch 的概念及 Centos 7 下详细安装步骤
打开淘宝, 搜索 狂飙 会出现各种价格有关狂飙的书籍, 当然也有高启强同款的孙子兵法!!! 如下图所示: 那么面对海量的数据, 如何快速且准确的找到我们想要的内容呢? 淘宝界面已经可以按照综合排序 / 销量 / 信用 / 价格等进行筛选, 是如何做到的呢? ElasticSearch 11 Elastic…...
04_Docker 镜像和仓库
04_Docker 镜像和仓库 文章目录04_Docker 镜像和仓库4.1 什么是 Docker 镜像4.2 列出 Docker 镜像4.3 拉取镜像4.4 查找镜像4.5 构建镜像4.5.1 创建 Docker Hub 账号4.5.2 用 Docker 的 commit 命令创建镜像4.5.3 用 Dockerfile 构建镜像4.5.5 基于 Dockerfile 构建新镜像4.5.5…...
postman-enterprise-API
Postman 是一个用于构建和使用 API 的 API 平台。Postman 简化了 API 生命周期的每个步骤并简化了协作,因此您可以更快地创建更好的 API。 API存储库 在一个中央平台上围绕您的所有 API 工件轻松存储、编目和协作。Postman 可以存储和管理 API 规范、文档、工作流配…...
【ESP 保姆级教程】玩转emqx MQTT篇② ——保留消息和遗嘱消息
忘记过去,超越自己 ❤️ 博客主页 单片机菜鸟哥,一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-02-18 ❤️❤️ 本篇更新记录 2023-02-18 ❤️🎉 欢迎关注 🔎点赞 👍收藏 ⭐️留言📝🙏 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请…...
开启慢查询日志方法
步骤 开启慢查询日志 SET GLOBAL slow_query_log on;SHOW VARIABLES like slow_query_log;设置时间限制 SET GLOBAL long_query_time 1; -- 单位sSHOW VARIABLES LIKE %long_query_time%;因为long_query_time参数只对新的数据库连接生效,所以还需要重启msql客户端…...
宝塔搭建实战人才求职管理系统admin前端vue源码(二)
大家好啊,我是测评君,欢迎来到web测评。 上一期给大家分享骑士cms后台端在宝塔的搭建部署方式,这套系统是前后端分离的架构,前端是用vue2开发的,还需要在本地打包手动发布上宝塔,所以本期给大家分享&#x…...
SpringMVC——基础知识
基本概念 SpringMVC是基于servlet api构造的原始web框架,全称是Spring Web MVC 而MVC的全称是Model View Controller,翻译成中文分别是“模型”,“视图”,“控制器”,这是一种软件的架构模式 Model:用来…...
论文浅尝 | SpCQL: 一个自然语言转换Cypher的语义解析数据集
笔记整理:郭爱博,国防科技大学博士论文发表会议:The 31th ACM International Conference on Information and Knowledge Management,CIKM 2022动机随着社交、电子商务、金融等行业的快速发展,现实世界编织出一张庞大而…...
MongoDB 使用规范与限制及最佳实践
MongoDB 灵活文档的优势 灵活库/集合命名及字段增减同一字段可存储不同类型数据Json 文档可多层次嵌套文档对于开发而言最自然的表达 MongoDB 灵活文档的烦恼 数据库集合字段名千奇百怪同一字段数据类型各不一样业务异常可能写入“脏”数据 1.1 库命名规范 不能为空字符串 &…...
第五十六章 树状数组(一)
第五十六章 树状数组一、前缀和的缺陷二、树状数组1、作用2、算法分析3、算法实现(1)lowbits()(2)插入(3)查询三、例题1、问题题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示2、代码一、前缀和…...
kubernetes教程 --Pod控制器详解
Pod控制器详解 介绍 Pod是kubernetes的最小管理单元,在kubernetes中,按照pod的创建方式可以将其分为两类: 自主式pod:kubernetes直接创建出来的Pod,这种pod删除后就没有了,也不会重建控制器创建的pod&am…...
N2750A Agilent Keysight HP 差分探头1.5GHz
N2750A Agilent Keysight HP 差分探头13554860890 N2750A 是 Agilent Keysight HP 的 1.5 GHz 差分探头。 特征: N2750A:1.5 GHz 衰减比:2:1 或 10:1(可切换) 动态范围: 5 V 或 10 Vpp(10:1 时…...
一文搞懂Linux内核进程CPU调度基本原理
为什么需要调度 进程调度的概念比较简单,我们假设在一个单核处理器的系统中,同一时刻只有一个进程可以拥有处理器资源,那么其他的进程只能在就绪队列中等待,等到处理器空闲之后才有计划获得处理器资源来运行。在这种场景下&#…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
起重机起升机构的安全装置有哪些?
起重机起升机构的安全装置是保障吊装作业安全的关键部件,主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理: 一、超载保护装置(核心安全装置) 1. 起重量限制器 功能:实时监测起升载荷&a…...
C++11 constexpr和字面类型:从入门到精通
文章目录 引言一、constexpr的基本概念与使用1.1 constexpr的定义与作用1.2 constexpr变量1.3 constexpr函数1.4 constexpr在类构造函数中的应用1.5 constexpr的优势 二、字面类型的基本概念与使用2.1 字面类型的定义与作用2.2 字面类型的应用场景2.2.1 常量定义2.2.2 模板参数…...
CVE-2023-25194源码分析与漏洞复现(Kafka JNDI注入)
漏洞概述 漏洞名称:Apache Kafka Connect JNDI注入导致的远程代码执行漏洞 CVE编号:CVE-2023-25194 CVSS评分:8.8 影响版本:Apache Kafka 2.3.0 - 3.3.2 修复版本:≥ 3.4.0 漏洞类型:反序列化导致的远程代…...
持续交付的进化:从DevOps到AI驱动的IT新动能
文章目录 一、持续交付的本质:从手动到自动的交付飞跃关键特性案例:电商平台的高效部署 二、持续交付的演进:从CI到AI驱动的未来发展历程 中国…...

