下面我给你一份 「从 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 风格关键点
- 构造 / 拷贝 / 析构齐全
- 提供
c_str() - 运算符重载
四、构造函数(最关键)
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 的差距在哪?
| 功能 | MyString | std::string |
|---|---|---|
| 动态扩容 | ❌ | ✅ |
| 移动语义 | ❌ | ✅ |
| SSO | ❌ | ✅ |
| 异常安全 | 一般 | 很强 |
| 性能优化 | 无 | 极强 |
十四、进阶可扩展(建议你练)
如果你想真正吃透 STL,可以继续实现👇
- 🔥
reserve()/capacity() - 🔥 自动扩容策略
- 🔥 移动构造 / 移动赋值
- 🔥
insert()/erase() - 🔥 Small String Optimization(SSO)
一句话总结(面试用)
STL 的 string 本质是一个 RAII 管理的动态字符数组,通过深拷贝、运算符重载和接口封装,实现安全高效的字符串操作。
发表回复