14人参与 • 2025-06-03 • C/C++
从零实现一个简易版std::string
namespace zzh { class string { private: char* _str; // 存储字符串的字符数组 size_t _size; // 当前字符串长度 size_t _capacity; // 已分配的容量 public: static const size_t npos; // 表示"不存在的位置" // 各类成员函数... }; }
这个自定义字符串类主要通过动态分配的字符数组_str
来存储字符串内容,并维护两个重要状态:_size
表示当前字符串长度,_capacity
表示已分配的内存容量。
1.基本成员变量
在自定义 string 类中,我们需要定义一些基本的成员变量来存储字符串的内容和相关信息:
_str
:用于存储字符串的字符数组,通常是一个动态分配的 char 类型数组。_size
:表示当前字符串的实际长度,不包括结尾的空字符 \0。_capacity
:表示分配的内存容量,通常大于或等于 _size,用于优化内存分配效率。2.构造函数和析构函数
构造函数用于初始化 string 对象,常见的构造方式包括:
3.赋值运算符重载
4.内存管理
5.迭代器支持
6.常见操作实现
追加字符或字符串:通过 push_back 和 append 方法,可以在字符串末尾添加字符或另一个字符串的内容。在实现时,需要注意内存容量是否足够,并在必要时进行扩展。
// 1. 从c风格字符串构造 string::string(const char* str) { _size = strlen(str); _str = new char[_size + 1]; _capacity = _size; memcpy(_str, str, _size + 1); } // 2. 拷贝构造函数 string::string(const string& s) { _size = s._size; _capacity = s._capacity; _str = new char[_capacity + 1]; memcpy(_str, s._str, _size + 1); } // 3. 析构函数 string::~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; }
关键点:
string& string::operator=(const string& s) { if (this != &s) { char* tmp = new char[s._capacity + 1]; memcpy(tmp, s._str, s._size + 1); delete[] _str; // 注意:原代码此处顺序有误,已修正 _str = tmp; _size = s._size; _capacity = s._capacity; } return *this; }
技术要点:
string::iterator string::begin() { return _str; } string::iterator string::end() { return _str + _size; }
说明:
begin()
返回字符串首地址end()
返回字符串末尾的下一个位置// 预分配内存 void string::reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; memcpy(tmp, _str, _size + 1); delete[] _str; _str = tmp; _capacity = n; } } // 追加字符 void string::push_back(char c) { if (_size >= _capacity) { size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity; reserve(newcapacity); } _str[_size++] = c; // 注意:原代码此处错误地写入了固定字符'c' _str[_size] = '\0'; }
内存管理策略:
reserve()
实现预分配,避免频繁扩容// 追加c风格字符串 void string::append(const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { size_t newcapacity = 2 * _capacity > _size + len ? 2 * _capacity : _size + len; reserve(newcapacity); } memcpy(_str + _size, str, len); // 注意:原代码此处多复制了一个终止符 _size += len; _str[_size] = '\0'; // 手动添加终止符 } // 查找字符 size_t string::find(char c, size_t pos = 0) const { for (size_t i = pos; i < _size; i++) { if (_str[i] == c) return i; } return npos; } // 插入字符 string& string::insert(size_t pos, char c) { assert(pos <= _size); if (_size >= _capacity) { size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity; reserve(newcapacity); } // 从后向前移动元素 for (size_t i = _size; i > pos; i--) _str[i] = _str[i - 1]; _str[pos] = c; _size++; return *this; }
核心算法:
append()
通过内存拷贝实现高效追加find()
线性查找目标字符insert()
通过元素后移实现插入操作memmove()
处理内存重叠情况// 比较运算符 bool string::operator<(const string& s) { size_t i1 = 0, i2 = 0; while (i1 < _size && i2 < s._size) { if (_str[i1] < s._str[i2]) return true; else if (_str[i1] > s._str[i2]) return false; i1++; i2++; } return i1 < s._size; // 注意:原代码此处逻辑有误,已修正 } // 索引运算符 char& string::operator[](size_t index) { assert(index < _size); return _str[index]; }
实现要点:
通过手写这个简易版string
类,我们深入理解了标准库字符串类的核心机制:动态内存管理、深拷贝实现、迭代器设计、扩容策略等。
虽然现代c++编程中应优先使用std::string
,但掌握这些底层原理有助于写出更高效、更安全的代码。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论