应优先使用std::string;仅在无stl、学习raii/深拷贝或调试内存时才手写字符串类,核心需掌握内存分配、c风格字符串桥接及拷贝/移动语义。

为什么不能直接用 std::string?
多数情况下你确实不该自己写字符串类——std::string 经过几十年打磨,兼顾安全、性能和标准兼容性。但如果你在写嵌入式系统(无 STL)、学习 RAII 和深拷贝机制,或调试内存问题时需要完全掌控字符存储逻辑,那手写一个最小可行的字符串类是有意义的。
关键不是“造轮子”,而是理解它背后三件事:内存如何分配、const char* 如何桥接、拷贝/移动语义怎么不崩。
MyString 的核心成员和构造函数怎么设?
最简版本只需要三个成员:char* 指向堆内存、size_t length 记长度、size_t capacity 记当前分配容量(避免每次追加都 realloc)。构造函数要覆盖四种常见场景:
-
MyString():空串,data_ = new char[1],data_[0] = '\0' -
MyString(const char* s):需判空,用strlen(s)算长度,分配len + 1字节 -
MyString(const MyString& other):必须深拷贝,不能只复制指针 -
MyString(MyString&& other) noexcept:移动构造,把other.data_指针拿过来后立刻置nullptr
漏掉 noexcept 或忘了置空被移动对象的指针,后续析构会 double-free。
赋值运算符重载最容易踩哪几个坑?
赋值不是构造,得处理自赋值、旧内存释放、异常安全。经典写法是“拷贝-交换”(copy-and-swap),但对简单类反而容易绕晕。更直白的做法是:
- 先检查
if (this == &other)防自赋值 - 用
delete[] data_清掉旧内存(注意:必须用[],否则未定义行为) - 再按构造逻辑分配新内存、拷贝内容
- 最后更新
length和capacity
如果中间 new 抛异常,data_ 已经是悬垂指针——所以更稳妥的是先 new,成功后再 delete[] 旧的。顺序不能反。
哪些接口必须提供才能算“可用”?
没有 c_str() 和 size(),这个类基本没法和其他代码交互;没有 operator== 和 operator+,连日志输出都费劲。最低限度补上:
-
const char* c_str() const { return data_; }(返回const指针,禁止外部改内部数据) size_t size() const { return length; }-
bool operator==(const MyString& rhs) const:用memcmp(data_, rhs.data_, length),别用strcmp(可能越界) -
MyString operator+(const MyString& rhs) const:返回新对象,不修改自身
别急着加 operator[] —— 如果不区分 const/non-const 版本,或者不检查下标,就等于主动引入 buffer overflow 风险。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











