跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

C++ STL String 类模拟实现详解

C++ STL String 类模拟实现涉及迭代器管理、内存分配、深拷贝与浅拷贝处理、运算符重载及常用接口逻辑。通过手写代码深入理解构造函数、析构函数、赋值操作符的 copy-and-swap 惯用法,以及 reserve、insert、erase 等函数的扩容策略与边界检查。掌握输入输出流重载细节,提升对底层内存模型和类型安全的认知。

王初壹发布于 2026/3/22更新于 2026/5/56 浏览
C++ STL String 类模拟实现详解

示意图

引言

此前我们探讨过 String 类的基础接口,也通过 OJ 题目熟悉了常用函数。今天我们来深入底层,模拟实现一下 String 类。这不仅能巩固 C++ 内存管理知识,还能理解 STL 容器背后的设计思想。

String 类的模拟实现

String 类在 STL 库出现之前就已存在,其接口设计对后续标准库影响深远。相比传统数据结构,它引入了迭代器等机制,更好地耦合了算法与对象。

迭代器与成员变量

我们先从迭代器入手,这是访问容器的核心方式。

class string {
public:
    typedef char* iterator;
    typedef const char* const_iterator;

    const char* c_str() const { return _str; }
    
    iterator begin() { return _str; }
    iterator end() { return _str + _size; }
    
    // const 版本,处理 const 修饰的对象时避免权限放大
    const_iterator begin() const { return _str; }
    const_iterator end() const { return _str + _size; }
    
    size_t size() const { return _size; }
    size_t capacity() const { return _capacity; }

private:
    char* _str = nullptr;
    size_t _size = 0;
    size_t _capacity = 0;
    static const size_t npos = -1;
};

注意 npos 通常定义为无符号整数的最大值,用于表示查找失败。这里为了简化直接初始化为 -1。

默认成员函数

构造函数、析构函数、拷贝构造和运算符重载是重点。标准库中有多个版本的构造函数,这里模拟了两个典型场景。

// 初始化 n 个字符 ch
string::string(size_t n, char ch) : _str(new char[n + 1]), _size(n), _capacity(n) {
    for (size_t i = 0; i < n; i++) {
        _str[i] = ch;
    }
    _str[_size] = '\0';
}

// 字符串初始化
string::string(const char* str) : _size(strlen(str)) {
    _capacity = _size;
    _str = new char[_size + 1];
    strcpy(_str, str);
}

// 析构函数
string::~string() {
    delete[] _str;
    _str = nullptr;
    _size = 0;
    _capacity = 0;
}

// 拷贝构造:深拷贝
string::string(const string& s) {
    _str = new char[s._capacity + 1];
    strcpy(_str, s._str);
    _size = s._size;
    _capacity = s._capacity;
}

// swap 函数:用于交换资源,提高效率
void string::swap(string& s) {
    std::swap(_str, s._str);
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
}

// 现代写法:利用 swap 实现拷贝构造(Copy-and-Swap 惯用法的变体)
string::string(const string& s) {
    string tmp(s._str); // 临时对象
    swap(tmp);
}

// 销毁内容
void clear() {
    _str[0] = '\0';
    _size = 0;
}

接下来是运算符重载部分,包括赋值、下标访问和比较运算。

// 赋值运算符重载:使用 Copy-and-Swap 保证异常安全
string& string::operator=(const string& s) {
    if (this != &s) {
        string tmp(s._str);
        swap(tmp);
    }
    return *this;
}

// [] 重载:非 const 版本
char& operator[](size_t pos) {
    assert(pos < _size);
    return _str[pos];
}

// [] 重载:const 版本
const char& operator[](size_t pos) const {
    assert(pos < _size);
    return _str[pos];
}

// 比较运算符
bool string::operator==(const string& s) const {
    return strcmp(_str, s._str) == 0;
}

bool string::operator!=(const string& s) const {
    return !(*this == s);
}

bool string::operator<(const string& s) const {
    return strcmp(_str, s._str) < 0;
}

bool string::operator<=(const string& s) const {
    return *this < s || *this == s;
}

bool string::operator>(const string& s) const {
    return !(*this <= s);
}

bool string::operator>=(const string& s) const {
    return !(*this < s);
}

常用函数接口

这里实现增删改查的核心逻辑,包括 reserve、push_back、append、insert、erase、find、substr 等。

// 预留空间
void string::reserve(size_t n) {
    if (n > _capacity) {
        char* tmp = new char[n + 1];
        strcpy(tmp, _str);
        delete[] _str;
        _str = tmp;
        _capacity = n;
    }
}

// 尾插单个字符
void string::push_back(char ch) {
    if (_size + 1 > _capacity) {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    _str[_size] = ch;
    ++_size;
    _str[_size] = '\0';
}

// 追加字符串
void string::append(const char* str) {
    size_t len = strlen(str);
    if (_size + len > _capacity) {
        size_t newCapacity = 2 * _capacity;
        if (_size + len > 2 * _capacity) {
            newCapacity = _size + len;
        }
        reserve(newCapacity);
    }
    strcpy(_str + _size, str);
    _size += len;
}

// += 重载
string& string::operator+=(char ch) {
    push_back(ch);
    return *this;
}

string& string::operator+=(const char* str) {
    append(str);
    return *this;
}

// 插入 n 个字符
void string::insert(size_t pos, size_t n, char ch) {
    assert(pos <= _size);
    assert(n > 0);
    if (_size + n > _capacity) {
        size_t newCapacity = 2 * _capacity;
        if (_size + n > 2 * _capacity) {
            newCapacity = _size + n;
        }
        reserve(newCapacity);
    }
    // 数据后移
    size_t end = _size + n;
    while (end > pos + n - 1) {
        _str[end] = _str[end - n];
        --end;
    }
    for (size_t i = 0; i < n; i++) {
        _str[pos + i] = ch;
    }
    _size += n;
}

// 插入字符串
void string::insert(size_t pos, const char* str) {
    size_t n = strlen(str);
    insert(pos, n, 'x'); // 复用上面的逻辑先占位
    for (size_t i = 0; i < n; i++) {
        _str[pos + i] = str[i];
    }
}

// 删除指定位置长度为 len 的字符串
void string::erase(size_t pos, size_t len) {
    if (len >= _size - pos) {
        _str[pos] = '\0';
        _size = pos;
    } else {
        size_t end = pos + len;
        while (end <= _size) {
            _str[end - len] = _str[end];
            ++end;
        }
        _size -= len;
    }
}

// 查找字符
size_t string::find(char ch, size_t pos) {
    for (size_t i = pos; i < _size; i++) {
        if (_str[i] == ch) {
            return i;
        }
    }
    return npos;
}

// 查找字符串
size_t string::find(const char* str, size_t pos) {
    const char* p = strstr(_str + pos, str);
    if (p == nullptr) {
        return npos;
    } else {
        return p - _str;
    }
}

// 截取子串
string string::substr(size_t pos, size_t len) {
    size_t leftLen = _size - pos;
    if (len > leftLen) len = leftLen;
    string tmp;
    tmp.reserve(len);
    for (size_t i = 0; i < len; i++) {
        tmp += _str[pos + i];
    }
    return tmp;
}

输入输出重载

最后处理流操作符重载,包括 <<、>> 以及 getline。

// 输出流重载
ostream& operator<<(ostream& out, const string& s) {
    for (auto ch : s) {
        out << ch;
    }
    return out;
}

// 输入流重载
istream& operator>>(istream& in, string& s) {
    s.clear();
    const size_t N = 1024;
    char buff[N];
    int i = 0;
    char ch = in.get();
    while (ch != ' ' && ch != '\n') {
        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;
}

// getline 输入直到指定分隔符
istream& getline(istream& in, string& s, char delim) {
    s.clear();
    const size_t N = 1024;
    char buff[N];
    int i = 0;
    char ch = in.get();
    while (ch != delim) {
        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;
}

总结

通过手写 String 类,我们重新审视了内存分配、深拷贝与浅拷贝的区别,以及 Copy-and-Swap 惯用法在赋值操作中的优势。同时,对扩容策略、边界检查以及类型安全的细节有了更深的体会。代码复用和逻辑优化是提升质量的关键,比如利用已有的 insert 逻辑来简化字符串插入的实现。在模仿中优化,在实战中学习,这才是掌握底层原理的正道。

目录

  1. 引言
  2. String 类的模拟实现
  3. 迭代器与成员变量
  4. 默认成员函数
  5. 常用函数接口
  6. 输入输出重载
  7. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • 前端面试核心知识点全解析
  • AI 编程工具深度对比:Cursor、Copilot、Trae 与 Claude Code
  • OpenClaw(龙虾机器人)本地部署技术指南
  • Meta Llama 3 发布:性能对标 GPT-4 的开源大模型技术解析
  • Seedance 2.0 飞书机器人集成安全合规与零信任加固方案
  • AI Agent 生产级框架实战:架构、记忆与工具调用详解
  • YOLO-DRONE 无人机低空巡检检测模型技术解析
  • Qwen-Image-Lightning 生成水墨中国风作品教程
  • 深度评测 GLM-5:代码生成实战体验
  • 读李宁《AIGC 自动化编程》:大模型辅助开发的分解与合并心法
  • 命令行 MCP 客户端实践:MCPHost 使用与模型兼容性测试
  • 大型语言模型在疾病诊断中的应用综述
  • AI 安全攻防:从深度伪造到深度信任的技术演进
  • LFM2.5-1.2B-Thinking 模型效果展示与性能分析
  • Flood Fill 算法原理及经典题目解析
  • FastAPI 打造基于 LLM 的 Web 接口实战教程
  • Docker Compose 常用命令详解
  • 基于 Django 和 Vue 的快递驿站收发管理系统
  • Claude Code 安装配置与实战教程
  • Lychee-Rerank 在统信 UOS 与申威 CPU 环境下的部署适配

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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