C++ 中的 string

[复制链接]
发表于 2026-1-3 15:34:43 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
目次

  • 焦点概念
  • 初始化与构造
  • 容量与属性
  • 元素访问与遍历

    • 访问单个字符
    • C 风格字符串
    • 遍历

  • 修改与操纵
  • 查找与子串
  • 范例转换

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

  • 当代化特性

    • C++17:std::string_view
    • C++20

  • 底层原理

    • SSO(Small String Optimization)
    • COW(Copy-On-Write)

  • 最佳实践

    • 参数通报
    • 性能优化
    • 安全性


本文首发于我的个人博客:Better Mistakes
版权声明:本文为原创文章,转载请附上原文出处链接及本声明。
由于技能迭代较快,文章内容大概随时更新(含勘误及增补)。为了确保您看到的是最新版本,并得到更好的代码阅读体验,请访问:
🍭 原文链接:https://bfmhno3.github.io/note/string-in-cpp/
std::string 是 C++ Standard Library 提供的标准类之一,这也是 C++ 开辟中最常用的类之一,它本质上是对 C 风格字符串(char*)的封装,提供了自动内存管理和丰富的操纵接口。
焦点概念

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

  • 头文件:#include
  • 定名空间:std
  • 特点:动态管理内存,自动处置惩罚扩容,兼容 C 风格字符串。
初始化与构造
  1. #include <string>
  2. #include <vector>
  3. std::string s1;                     // 默认构造,空字符串 ""
  4. std::string s2 = "Hello, World";    // 拷贝初始化
  5. std::string s3("Hello, World");     // 直接初始化
  6. std::string s4(5, 'A');             // 生成 "AAAAA"
  7. std::string s5(s2);                 // 拷贝构造
  8. std::string s6(s2, 1, 3);           // 子串构造:从索引 1 开始取 3 个字符 -> "ell"
  9. // C++11 及以后
  10. 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。不查抄越界,服从高,但越界为导致未界说活动。
  • at():s.at。查抄越界,越界会抛出 std:ut_of_range 非常。
  • front() / back():访问首尾字符。
C 风格字符串


  • c_str():返回 const char*,以 NULL 末了。紧张用于兼容旧式 C 接口(如 printf)。
  • data():C++11 前不包管 NULL 末了,C++11 后与 c_str() 根本同等。
遍历
  1. std::string s = "Hello, World";
  2. // 1. 基于下标
  3. for (size_t i = 0; i < s.size(); ++i) { /* ... */ }
  4. // 2. 基于迭代器
  5. for (auto it = s.begin(); it != s.end(); ++i) { /* ... */}
  6. // 3. 基于范围 for 循环(C++11,推荐)
  7. for (char c: s) { /* ... */ }       // 值拷贝
  8. 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())。
  1. std::string = "filename.txt";
  2. // 1. 查找 find
  3. size_t pos = s.find(".");
  4. if (pos != std::string::npos) {
  5.     // 找到了
  6. }
  7. // 2. 反向查找 rfind(找最后一个出现的位置)
  8. size_t last_dot = s.rfind(".");
  9. // 3. 查找集合 find_first_of / find_first_not_of
  10. // 查找第一个出现的元音字母
  11. size_t v_pos = s.find_first_of("aeiou");
  12. // 4. 获取子串 substr
  13. // 参数:substr(开始位置, 长度)
  14. std::string name = s.substr(0, pos); // "filename"
  15. std::string ext = s.substr(pos + 1); // "txt"(省略长度则取到末尾)
复制代码
范例转换

必要包罗头文件 。
数值转字符串 std::to_string(value)
  1. 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&,特殊是当你只必要读取字符串内容时。
  1. // 避免了临时 std::string 对象的构造和内存分配
  2. void print_prefix(std::string_view sv) {
  3.     i f(sv.substr(0, 3) == "Pre") { // substr 也是 O(1) 操作
  4.         // ...
  5.     }
  6. }
复制代码
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 订阅我的最新动态!
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表