C++ 中的 string

文章目录

本文首发于我的个人博客:Better Mistakes

版权声明:本文为原创文章,转载请附上原文出处链接及本声明。
由于技术迭代较快,文章内容可能随时更新(含勘误及补充)。为了确保您看到的是最新版本,并获得更好的代码阅读体验,请访问:

🍭 原文链接https://bfmhno3.github.io/note/string-in-cpp/

std::string 是 C++ Standard Library 提供的标准类之一,这也是 C++ 开发中最常用的类之一,它本质上是对 C 风格字符串(char*)的封装,提供了自动内存管理和丰富的操作接口。

核心概念

std::string 位于 <string> 头文件中,本质上是对 std::basic_string<char> 的特化版本。

  • 头文件:#include <string>
  • 命名空间:std
  • 特点:动态管理内存,自动处理扩容,兼容 C 风格字符串。

初始化与构造

#include<string>#include<vector> std::string s1;// 默认构造,空字符串 "" std::string s2 ="Hello, World";// 拷贝初始化 std::string s3("Hello, World");// 直接初始化 std::string s4(5,'A');// 生成 "AAAAA" std::string s5(s2);// 拷贝构造 std::string s6(s2,1,3);// 子串构造:从索引 1 开始取 3 个字符 -> "ell"// C++11 及以后 std::string s7 ={'H','i'};// 列表初始化

容量与属性

了解容量对于优化性能至关重要,特别是避免不必要的内存重分配。

函数说明备注
size() / length()返回字符数量两者完全等价,一般用 size()
empty()判断是否为空推荐使用,比 size() == 0 语义更清晰
capacity()当前分配的内存容量通常 >=size()
reserve(n)预分配 n 字节内存避免 append 时的多次内存重分配
shrink_to_fit()释放多余内存(C++11)capacity 接近 size

元素访问与遍历

访问单个字符

  • operator[]s[i]不检查越界,效率高,但越界为导致未定义行为。
  • at()s.at[i]检查越界,越界会抛出 std::out_of_range 异常。
  • front() / back():访问首尾字符。

C 风格字符串

  • c_str():返回 const char*,以 NULL 结尾。主要用于兼容旧式 C 接口(如 printf)。
  • data():C++11 前不保证 NULL 结尾,C++11 后与 c_str() 基本一致。

遍历

std::string s ="Hello, World";// 1. 基于下标for(size_t i =0; i < s.size();++i){/* ... */}// 2. 基于迭代器for(auto it = s.begin(); it != s.end();++i){/* ... */}// 3. 基于范围 for 循环(C++11,推荐)for(char c: s){/* ... */}// 值拷贝for(char& c: s){ c =toupper(c)}// 引用修改

修改与操作

操作函数示例
追加+=append()push_back()s += " World"
插入insert(pos, str)s.insert(0, "Hi ")
删除erase(pos, len), pop_back()s.erase(0, 3)
替换replace(pos, len, str)s.replace(6, 5, "C++")
清空clear()size 设置为 0,capacity 通常不变
截断/扩充resize(n)改变 size,多出的补默认值

查找与子串

所有查找函数如果未找到,都会返回常量 std::string::npos(通常是 -1 的无符号形式,即最大的 size_t())。

std::string ="filename.txt";// 1. 查找 find size_t pos = s.find(".");if(pos != std::string::npos){// 找到了}// 2. 反向查找 rfind(找最后一个出现的位置) size_t last_dot = s.rfind(".");// 3. 查找集合 find_first_of / find_first_not_of// 查找第一个出现的元音字母 size_t v_pos = s.find_first_of("aeiou");// 4. 获取子串 substr// 参数:substr(开始位置, 长度) std::string name = s.substr(0, pos);// "filename" std::string ext = s.substr(pos +1);// "txt"(省略长度则取到末尾)

类型转换

需要包含头文件 <string>

数值转字符串 std::to_string(value)

std::string s = std::to_string(3.14);// "3.140000"

字符串转数值

  • std::stoi(s)int
  • std::stol(s)long
  • std::stod(s)double
  • 注意:这些函数会处理前导空格,但遇到非法字符会抛异常

现代化特性

C++17:std::string_view

std::string 是 “拥有者”,其拷贝开销大。std::string_view 只是一个 “观察者”(包含指针和长度),零拷贝。

函数参数尽量使用 std::string_view 代替 const std::string&,特别是当你只需要读取字符串内容时。

// 避免了临时 std::string 对象的构造和内存分配voidprint_prefix(std::string_view sv){ i f(sv.substr(0,3)=="Pre"){// substr 也是 O(1) 操作// ...}}

C++20

填补了长期以来 C++ std::string 缺少高频接口的遗憾:

  • s.starts_with("prefix"):判断前缀
  • s.ends_with("suffix"):判断后缀
  • s.contains("sub"):判断包含

底层原理

SSO(Small String Optimization)

原理:为了避免短字符串频繁的堆内存分配(Heap Allocation),std::string 内部通常有一个小的栈缓冲区(通常 15 或 22 字节,取决于编译器实现)。

效果

  • 如果字符串很短(例如:"Hello"),直接存放在栈上对象内部,无 malloc,速度极快。
  • 如果字符串变长,才会在堆上分配内存,指针指向堆。

COW(Copy-On-Write)

在 C++11 之后已被废弃。现在的标准规定 std::string 不允许使用 COW。这意味着 std::string a = b; 一定会发生深拷贝(除非使用 std::move)。

最佳实践

参数传递

  • 只读不拥有:C++17 前用 const std::string&,C++17 后优先用 std::string_view
  • 需要修改:用 std::string&
  • 需要拥有权(Sink):可以直接传值 std::string 并配合 std::move

性能优化

  • 在循环中追加字符串前,先用 reserve() 预留空间(写在循环之前)。
  • 尽量避免在循环内部频繁构造 std::string
  • 换行符优先用 \n 而不是 std::endl(除非你需要立即刷新缓冲区)。

安全性

  • 永远不要对 c_str() 返回的指针进行 delete 操作。
  • string 对象被修改或销毁后,之前获取的 iterators、references 和 pointers(如 c_str() 的结果)可能会失效。

📢 写在最后

如果你觉得这篇文章对你有帮助,欢迎到我的个人博客 Better Mistakes 逛逛。

在那里我归档了更多高质量的技术文章,也欢迎通过 RSS 订阅我的最新动态!

Read more

Apache IoTDB(5):深度解析时序数据库 IoTDB 在 AINode 模式单机和集群的部署与实践

Apache IoTDB(5):深度解析时序数据库 IoTDB 在 AINode 模式单机和集群的部署与实践

引言 Apache IoTDB 设计之初就专为物联网(IoT)场景而生,旨在提供一个集高性能数据写入、海量数据存储、低延迟分析查询于一体的一站式解决方案。 Apache IoTDB 时序数据库【系列篇章】: No.文章地址(点击进入)1Apache IoTDB(1):时序数据库介绍与单机版安装部署指南2Apache IoTDB(2):时序数据库 IoTDB 集群安装部署的技术优势与适用场景分析3Apache IoTDB(3):时序数据库 IoTDB Docker部署从单机到集群的全场景部署与实践指南4Apache IoTDB(4):深度解析时序数据库 IoTDB 在Kubernetes 集群中的部署与实践指南 一、IoTDB——AINode介绍 AINode 是 IoTDB 在 ConfigNode、DataNode 后提供的第三种内生节点,通过与 IoTDB 集群的 DataNode、

By Ne0inhk
wsl2下Ubuntu获得完整桌面体验(WSLg+KDE)

wsl2下Ubuntu获得完整桌面体验(WSLg+KDE)

wsl2下Ubuntu获得完整桌面体验(WSLg+KDE) 不使用Xvnc或Xorg,本教程参考 Full desktop shell in WSL2 using WSLg (XWayland)-github 无需安装其他软件,全程在wsl2中实现 环境 windows10专业版22H2 wsl:2.6.3.0 Ubuntu:24.04.3 LTS KDE:5(XWayland只支持这个) 前言 很久以前就在想要是能同时操作Windows和Linux而不用双系统就好了,现在通过WSL2实现了体验不错的双桌面系统,至少在我的笔记本上,wsl的体验要比在VBox或者VM强,还有显卡直通,要舒服的多。 参考了Github上的教程,但是他只做了GNOME桌面的教程,由于我的电脑分辨率是非整数倍缩放,而GNOME对于非整数倍缩放的支持异常糟糕,而且打开设置竟然要10秒以上,太臃肿了,所以我换成了KDE,写下这篇文章。 需要注意的是一旦使用了这个教程,WSLg将全权被桌面接管,无法体验Windows与linux那种无缝交互的感觉,即应用直接投影到桌面,

By Ne0inhk
Ubuntu_24.04 安装OpenClaw教程

Ubuntu_24.04 安装OpenClaw教程

认识OpenClaw 官网:https://openclaw.ai/ https://docs.openclaw.ai/start/getting-started 安装OpenClaw curl -fsSL https://openclaw.ai/install.sh | bash 安装完成 配置命令 在终端输入: openclaw onboard 选择Yes 选择QuickStart 因为前面配置过,所以提示是否用原来的配置信息,可以使用Reset进行重置 选择模型: 根据自己的需要进行选择, 这里要特别注意一个问题,openClaw对上下文有要求,默认最小是16000Token,要不然后面安装的时候会报下图的错误信息 选择Qwen一直在waiting 如果要使用其他的模型,选择Custom Provider 如果选择DeepSeek,baseURL输入:https://api.deepseek.com/v1 然后输入API-KEY:sk-******* model输入:

By Ne0inhk
20-OpenClaw定时任务与自动化工作流

20-OpenClaw定时任务与自动化工作流

OpenClaw 定时任务与自动化工作流 ✦ 免费专栏|全套教程: OpenClaw 从入门到精通 ✦ 开篇总览|最新目录: 最新 OpenClaw 教程|从入门到精通|AI 智能助手 / 自动化 / Skills 实战(原 Clawdbot/Moltbot) 本文档详细介绍 OpenClaw 的定时任务和自动化功能,包括 Cron 配置、Heartbeat 心跳机制以及自动化工作流的设计与实践。 目录 1. 概述 2. Cron 定时任务配置 3. Heartbeat 心跳机制 4. 自动化工作流设计 5. 实战案例 6. 最佳实践与注意事项 1. 概述 OpenClaw 提供了强大的定时任务和自动化能力,让 AI 助手能够主动执行任务,

By Ne0inhk