跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

STL string 类源码实现详解

从零模拟实现 C++ STL string 类。涵盖构造函数、拷贝构造与赋值运算符的深拷贝策略(传统写法与 Copy-and-Swap)、迭代器设计、容量管理(reserve/capacity)、字符串修改(push_back/insert/erase)及输入输出流重载。重点解析内存分配机制、自我赋值保护及边界条件处理,帮助深入理解底层数据结构与资源管理。

苹果系统发布于 2026/3/30更新于 2026/6/513 浏览
STL string 类源码实现详解

概述

在掌握 string 接口后,我们尝试从零实现一个完整的 string 类。为了避免与标准库冲突,这里使用 mystd 命名空间封装。

核心成员与迭代器

类内部主要维护三个私有成员:

  • _str: 指向动态分配的字符数组。
  • _size: 当前有效字符长度(不含 \0)。
  • _capacity: 当前分配的总容量(不含 \0)。 此外定义 npos 为无符号整型最大值,用于表示查找失败等异常状态。 迭代器直接复用指针类型别名,iterator 对应 char*,const_iterator 对应 const char*。

默认成员函数实现

构造函数

无参构造时,需预留一个 \0 作为空串标识,此时 _size 和 _capacity 均为 0。带参构造则根据传入 C 字符串长度计算所需空间,注意额外分配一位给终止符。

// 无参构造
string() : _str(new char[1]{'\0'}), _size(0), _capacity(0) {}

// 带参构造
string(const char* str) {
    _size = strlen(str);
    _capacity = _size;
    _str = new char[_capacity + 1];
    strcpy(_str, str);
}

注:初始化列表顺序遵循成员声明顺序,但此处为了复用 strlen 结果,直接在函数体内计算更为直观。

析构函数

释放动态内存并重置状态。

~string() {
    delete[] _str;
    _size = 0;
    _capacity = 0;
}

深拷贝与赋值策略

拷贝构造函数

浅拷贝会导致多个对象共享同一块内存,析构时引发重复释放错误。必须实现深拷贝,为新对象独立分配内存并复制内容。

传统写法如下:

string(const string& s) : _size(s._size), _capacity(s._size) {
    _str = new char[_capacity + 1];
    strcpy(_str, s._str);
}

现代推荐写法采用 Copy-and-Swap 惯用法,利用临时对象完成深拷贝后再交换,能自动处理资源清理且代码更简洁:

void swap(string& tmp) {
    std::swap(_str, tmp._str);
    std::swap(_size, tmp._size);
    std::swap(_capacity, tmp._capacity);
}

string(const string& s) {
    string tmp(s); // 调用拷贝构造创建临时对象
    swap(tmp);     // 交换资源
}

注意:若未对成员变量赋初值(如 nullptr),在交换前确保临时对象已正确初始化,否则可能导致悬空指针。

赋值运算符重载

同样面临深浅拷贝问题,且需防范自我赋值。 传统方式需先检查 this == &other,再释放旧内存并申请新内存。 Copy-and-Swap 版本通过按值传递参数,隐式触发拷贝构造生成临时副本,随后交换即可,无需手动 delete。

string& operator=(string tmp) {
    swap(tmp);
    return *this;
}

这种写法不仅安全,还天然支持链式赋值。

迭代器与访问

迭代器本质是指针。begin() 返回首字符地址,end() 返回最后一个字符后的位置(即 \0 处)。 下标运算符 operator[] 提供读写与只读两个版本,需断言下标有效性。

iterator begin() { return _str; }
const_iterator end() const { return _str + _size; }
char& operator[](size_t i) { assert(i < _size); return _str[i]; }

容量与大小管理

size() 和 capacity() 分别返回当前长度与容量。 reserve(n) 负责扩容,当请求容量大于当前容量时,重新分配更大内存并拷贝旧数据。一般只扩不缩,避免频繁分配开销。 empty() 判断是否为空,可通过比较 _size 是否为零实现,比调用 strcmp 更高效。

void reserve(size_t n) {
    if (n > _capacity) {
        char* tmp = new char[n + 1];
        strcpy(tmp, _str);
        delete[] _str;
        _str = tmp;
        _capacity = n;
    }
}
bool empty() const { return _size == 0; }

字符串修改操作

尾插与追加

push_back(char c) 在末尾添加字符。若空间不足,采用二倍扩容策略。插入后记得补上 \0。 append(const char* s) 追加字符串,逻辑类似,需注意目标缓冲区剩余空间。 operator+= 可复用上述函数简化实现。

void push_back(char c) {
    if (_size == _capacity) {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    _str[_size++] = c;
    _str[_size] = '\0';
}

插入与删除

insert(pos, ...) 涉及中间位置的数据移动。 插入字符时,从尾部开始逐个向后挪动,腾出位置。注意 size_t 无符号特性,循环条件应设为 end > pos 而非 end >= pos,防止头部插入时 end 减至 0 后发生下溢变成极大正数导致死循环。 插入字符串同理,先移动尾部 \0 及后续字符,再填入新内容。 erase(pos, len) 删除指定范围字符,将后续字符向前覆盖。若删除至末尾,只需截断。

void insert(size_t pos, char c) {
    assert(pos <= _size);
    if (_size == _capacity) {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    size_t end = _size + 1;
    while (end > pos) {
        _str[end] = _str[end - 1];
        --end;
    }
    _str[pos] = c;
    _size++;
}

substr 截取子串,新建 string 对象并填充数据。 clear 仅将首字符置为 \0 并重置长度,不释放内存,效率更高。

string substr(size_t pos, size_t len) {
    assert(pos < _size);
    if (len >= _size - pos) len = _size - pos;
    string tmp;
    tmp.reserve(len);
    for (size_t i = 0; i < len; ++i) {
        tmp += _str[pos + i];
    }
    return tmp;
}

查找与比较

find 支持查找字符或子串。字符查找线性扫描即可;子串查找可利用 strstr 辅助,返回相对偏移量。 关系运算符重载中,只需实现 < 和 ==,其余可通过组合推导得出,减少冗余代码。

bool operator<(const string& s1, const string& s2) {
    return strcmp(s1.c_str(), s2.c_str()) < 0;
}
bool operator==(const string& s1, const string& s2) {
    return strcmp(s1.c_str(), s2.c_str()) == 0;
}

输入输出流

重载 >> 和 << 使 string 能配合标准流使用。 输入时跳过前导空白,读取非空白字符直到遇到分隔符。为避免频繁扩容,可使用局部缓冲数组暂存。 输出时遍历字符逐个写入流。

istream& operator>>(istream& in, string& s) {
    s.clear();
    const int N = 256;
    char buff[N] = { 0 };
    int i = 0;
    char ch = in.get();
    while (ch == ' ' || ch == '\n' || ch == '\t') ch = in.get();
    while (ch != ' ' && ch != '\n' && ch != '\t') {
        buff[i++] = ch;
        if (i == N - 1) { buff[i] = '\0'; s += buff; i = 0; }
        ch = in.get();
    }
    if (i > 0) { buff[i] = '\0'; s += buff; }
    return in;
}
ostream& operator<<(ostream& out, const string& s) {
    for (auto ch : s) out << ch;
    return out;
}

这样实现了一个功能完备的 string 类,涵盖了内存管理、资源获取即初始化(RAII)思想以及常用算法逻辑。

目录

  1. 概述
  2. 核心成员与迭代器
  3. 默认成员函数实现
  4. 构造函数
  5. 析构函数
  6. 深拷贝与赋值策略
  7. 拷贝构造函数
  8. 赋值运算符重载
  9. 迭代器与访问
  10. 容量与大小管理
  11. 字符串修改操作
  12. 尾插与追加
  13. 插入与删除
  14. 查找与比较
  15. 输入输出流
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • HuggingFace 镜像与反向代理加速 GLM-4.6V-Flash-WEB 模型加载
  • 基于 Python 的跨境电商数据采集实战与代理 IP 应用
  • Python 通达信数据获取技术解析与应用
  • CoPaw 个人助理部署与使用指南:从零搭建专属 AI 数字搭档
  • IT 行业热门岗位薪资分析与 Python 学习路线指南
  • Python 调用高德地图 MCP 服务查询天气示例
  • 闲鱼 x-sign 生成算法逆向分析
  • GLM-5 与 Qwen3.5 双模型对比:一句话生成 HTML 小游戏
  • Windows 安装 Docker 解决 No default Boot2Docker ISO found locally 错误
  • OpenClaw 本地部署:Web 面板调试与大模型集成
  • AI 入门:常见术语解释与误区澄清
  • AI 数据标注平台选型与实践:效率提升背后的技术逻辑
  • 普通人如何靠提问和评论参与 AI 创作?
  • 常见 AIGC 检测规避工具与方法介绍
  • 算法模拟专题:LeetCode 精选例题解析
  • Python 月相可视化系统:天文计算与 Web 界面实现
  • 前端 Canvas 基础与实战应用
  • SRC 漏洞挖掘实战指南:信息收集、逻辑漏洞与绕过技巧
  • AgentScope Java 多智能体框架
  • AI 在前端工作中的应用

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online