菜鸟-创作你的创作

【C++】手搓一个STL风格的string容器 

下面我给你一份 「从 0 手搓一个 STL 风格的 string 容器」完整教程
目标是:写出来的 MyString 用法、风格、思想都尽量贴近 std::string,而且小白也能看懂

适合人群
✅ C++ 初学 → 进阶
✅ 理解 STL 底层实现
✅ 面试 / 数据结构 / 手写容器


一、目标:我们要做什么?

我们要实现一个 STL 风格的字符串容器

MyString s1("hello");
MyString s2 = s1;
s2 += " world";

cout << s2 << endl;   // hello world
cout << s2.size();   // 11

具备以下能力 👇

功能是否实现
动态内存管理
构造 / 拷贝 / 析构
运算符重载
下标访问
size() / c_str()
RAII 思想

二、STL string 的核心思想(先懂原理)

std::string 本质是什么?

👉 一个动态 char 数组 + 长度管理

核心成员(简化版):

char* _data;   // 指向堆内存
size_t _size; // 当前字符串长度
size_t _cap;  // 容量


为什么不用 char str[100]

❌ 固定大小
❌ 容易溢出
❌ 不安全

👉 STL string:自动扩容 + 安全 + 面向对象


三、定义 MyString 类(第一步)

#pragma once
#include <iostream>
#include <cstring>

class MyString {
public:
    // 构造函数
    MyString(const char* str = "");

    // 拷贝构造
    MyString(const MyString& other);

    // 拷贝赋值
    MyString& operator=(const MyString& other);

    // 析构
    ~MyString();

    // 容量相关
    size_t size() const;
    const char* c_str() const;

    // 运算符
    char& operator[](size_t index);
    const char& operator[](size_t index) const;

    MyString& operator+=(const char* str);

private:
    char* _data;
    size_t _size;
};

📌 STL 风格关键点


四、构造函数(最关键)

MyString::MyString(const char* str) {
    if (str == nullptr) {
        _size = 0;
        _data = new char[1];
        _data[0] = '\0';
    } else {
        _size = strlen(str);
        _data = new char[_size + 1];
        strcpy(_data, str);
    }
}

为什么要 +1

👉 给 '\0' 留空间(C 风格字符串结尾)


五、析构函数(RAII)

MyString::~MyString() {
    delete[] _data;
}

👉 谁申请,谁释放


六、拷贝构造(深拷贝)

❌ 错误做法(浅拷贝):

_data = other._data; // ❌

✅ 正确做法:

MyString::MyString(const MyString& other) {
    _size = other._size;
    _data = new char[_size + 1];
    strcpy(_data, other._data);
}

📌 避免多个对象指向同一块内存


七、拷贝赋值运算符(重点 ⭐)

标准写法(防自赋值)

MyString& MyString::operator=(const MyString& other) {
    if (this != &other) {
        delete[] _data;

        _size = other._size;
        _data = new char[_size + 1];
        strcpy(_data, other._data);
    }
    return *this;
}


八、下标运算符(像数组一样用)

char& MyString::operator[](size_t index) {
    return _data[index];
}

const char& MyString::operator[](size_t index) const {
    return _data[index];
}

👉 支持:

s[0] = 'H';
cout << s[1];


九、size() / c_str()

size_t MyString::size() const {
    return _size;
}

const char* MyString::c_str() const {
    return _data;
}


十、字符串拼接 +=

MyString& MyString::operator+=(const char* str) {
    if (str == nullptr) return *this;

    size_t len = strlen(str);
    char* newData = new char[_size + len + 1];

    strcpy(newData, _data);
    strcpy(newData + _size, str);

    delete[] _data;
    _data = newData;
    _size += len;

    return *this;
}

📌 STL 风格:返回引用,支持链式调用


十一、输出运算符(像 cout 一样用)

std::ostream& operator<<(std::ostream& os, const MyString& s) {
    os << s.c_str();
    return os;
}


十二、完整测试代码

int main() {
    MyString s1("hello");
    MyString s2 = s1;

    s2 += " world";

    std::cout << s1 << std::endl;
    std::cout << s2 << std::endl;
    std::cout << s2.size() << std::endl;

    s2[0] = 'H';
    std::cout << s2 << std::endl;

    return 0;
}

输出:

hello
hello world
11
Hello world

✅ 成功!


十三、和 std::string 的差距在哪?

功能MyStringstd::string
动态扩容
移动语义
SSO
异常安全一般很强
性能优化极强

十四、进阶可扩展(建议你练)

如果你想真正吃透 STL,可以继续实现👇


一句话总结(面试用)

STL 的 string 本质是一个 RAII 管理的动态字符数组,通过深拷贝、运算符重载和接口封装,实现安全高效的字符串操作。

退出移动版