容器 string 的模拟实现
- 开篇解释
- 代码实现:
- myString.h 头文件
- myString.cpp 实现文件
模拟实现 string
能对 STL 有更深刻的认识,底层了解越丰富,使用起来越顺手
接下来我会以 .h
头文件以及其 .cpp
的实现文件展示其大致模拟,这只是遵循 STL 的功能来模拟的而已,实际上的细节、效率以及设计方式自然是比不过库里大佬所写的
开篇解释
首先,string
作为一个对象,最主要的属性就是 字符串本身(堆上空间) 、 字符串长度 和 为字符串所开辟出来的空间大小 :
这里要注意:
_str
是指针, 指向堆上的一块空间 ,字符串就存储在这块空间里- 字符串与 C 语言的字符串一样 其末尾均有
'\0'
,别无二致 _size
始终指示 字符串的长度 ,随其长度动态变化,不包含 字符串末尾空字符'\0'
_capacity
始终指示 为字符串开辟的空间大小 ,随其长度动态变化, 包含 空间末尾空字符'\0'
- 注意:为防止可能的越界 bug ,为字符串开辟的空间末尾始终含有
'\0'
,字符串本身末尾也含有'\0'
我这里为字符串实现的扩容没有按照 g++ 或者 vs 约定俗成的 2 倍扩容之类的 ,只是单纯的空间不够就扩容,当然如果想实现,也可以写一个额外的 功能函数 ( 要兼容拼接长字符串 ),只是要注意接口为 private
私有
因为我的类名也是 string
,所以在 myString.h
头文件里 最好标识命名空间 ,我写在了名为 what
的命名空间里
接下来就没什么了,实现代码:
代码实现:
以下代码为 vs2019 测试 ,如有 Bug 欢迎指正 ^ ^
myString.h 头文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
namespace what
{
class string
{
public:
// Constructors: *************************************
string(const char* pStr = "");
string(const string& str);
// Destructor: ****************************************
~string();
// operator= ******************************************
string& operator=(const char* str);
string& operator=(const string& str);
string& operator= (char c);
// Iterators: *****************************************
typedef char* iterator;
typedef const char* const_iterator;
typedef char* reverse_iterator;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin() const;
reverse_iterator rend() const;
// Capacity: ********************************************
size_t size() const;
size_t capacity() const;
void resize(size_t n, char c = '\0');
void reserve(size_t n = 0);
void clear();
bool empty() const;
// Element access: ***************************************
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
// Modifiers: *******************************************
string& operator+=(const string& str);
string& operator+=(const char* str);
string& operator+=(char c);
string& append(const string& str);
string& append(const char* str, size_t n);
// 有了 += 的功能,剩下的 append 很好实现,自己试试咯
void push_back(char c);
void swap(string& str);
string& insert(size_t pos, const string& str);
string& erase(size_t pos = 0, size_t len = npos);
// String operations: ************************************
const char* c_str() const;
const char* data() const;
size_t copy(char* s, size_t len, size_t pos = 0) const;
size_t find(char c, size_t pos = 0) const;
size_t find(const char* s, size_t pos = 0) const;
string substr(size_t pos = 0, size_t len = npos) const;
private:
char* _str = nullptr;
size_t _size = 0;
size_t _capacity = 0;
public:
static const size_t npos;
};
// Non-member function overloads: *******************************************
string operator+(const string& lhs, const string& rhs);
bool operator==(const string& lhs, const string& rhs);
bool operator!=(const string& lhs, const string& rhs);
bool operator<(const string& lhs, const string& rhs);
bool operator<=(const string& lhs, const string& rhs);
bool operator>(const string& lhs, const string& rhs);
bool operator>=(const string& lhs, const string& rhs);
void swap(string& x, string& y);
std::istream& operator>>(std::istream& is, string& str);
std::ostream& operator<<(std::ostream& os, const string& str);
std::istream& getline(std::istream& is, string& str, char delim = '\n');
}
myString.cpp 实现文件
#include "myString.h"
const size_t what::string::npos = -1;
what::string::string(const char* pStr)
{
_size = strlen(pStr);
_capacity = _size + 2;
_str = new char[_capacity];
strcpy(_str, pStr);
_str[_capacity - 1] = '\0';
}
what::string::string(const string& str)
: _size(strlen(str._str))
{
_capacity = _size + 2;
_str = new char[_capacity];
strcpy(_str, str._str);
_str[_capacity - 1] = '\0';
}
// 拷贝构造的现代写法
//what::string::string(const string& str)
//{
// string tmp(str.c_str());
// swap(tmp);
//}
// Destructor: ****************************************
what::string::~string()
{
delete[] _str;
_size = _capacity = 0;
}
// operator= ******************************************
what::string& what::string::operator=(const char* str)
{
_size = strlen(str);
if (_capacity - 1 < _size + 1)
{
_capacity = _size + 2;
char* tmp = new char[_capacity];
strcpy(tmp, str);
delete[] _str;
_str = tmp;
_str[_capacity - 1] = '\0';
}
else
strcpy(_str, str);
return *this;
}
what::string& what::string::operator=(const string& str)
{
_size = str._size;
if (_capacity - 1 < _size + 1)
{
_capacity = _size + 2;
char* tmp = new char[_capacity];
strcpy(tmp, str._str);
delete[] _str;
_str = tmp;
_str[_capacity - 1] = '\0';
}
else
strcpy(_str, str._str);
return *this;
}
// 赋值重载的现代写法
//what::string& what::string::operator=(string str)
//{
// swap(str);
// return *this;
//}
what::string& what::string::operator= (char c)
{
delete[] _str;
_size = 1;
_capacity = _size + 2;
_str = new char[_capacity];
_str[0] = c;
_str[_size] = '\0';
_str[_capacity - 1] = '\0';
return *this;
}
// Iterators: *****************************************
typedef char* iterator;
typedef const char* const_iterator;
typedef char* reverse_iterator;
iterator what::string::begin()
{
return _str;
}
const_iterator what::string::begin() const
{
return _str;
}
iterator what::string::end()
{
return _str + _size;
}
const_iterator what::string::end() const
{
return _str + _size;
}
reverse_iterator what::string::rbegin() const
{
return _str + _size - 1;
}
reverse_iterator what::string::rend() const
{
return _str - 1;
}
// Capacity: ********************************************
size_t what::string::size() const
{
return _size;
}
size_t what::string::capacity() const
{
return _capacity;
}
void what::string::resize(size_t n, char c)
{
if (n > _size)
{
if (n > _capacity - 2)
reserve(n);
for (size_t i = _size; i < n; ++i)
_str[i] = c;
}
_size = n;
_str[_size] = '\0';
}
void what::string::reserve(size_t n)
{
if (n > _capacity - 2)
{
_capacity = n + 2;
char* tmp = new char[_capacity];
strcpy(tmp, _str);
delete _str;
_str = tmp;
_str[_capacity - 1] = '\0';
}
}
void what::string::clear()
{
_size = 0;
_str[_size] = '\0';
}
bool what::string::empty() const
{
return _size == 0;
}
// Element access: ***************************************
char& what::string::operator[] (size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& what::string::operator[] (size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
// Modifiers: *******************************************
what::string& what::string::operator+=(const what::string& str)
{
size_t totalSize = _size + str._size;
if (_capacity - 1 < totalSize + 1)
reserve(totalSize);
size_t k = 0;
for (size_t i = _size; i < totalSize; ++i)
_str[i] = str._str[k++];
_size = totalSize;
_str[_size] = '\0';
return *this;
}
what::string& what::string::operator+=(const char* str)
{
size_t totalSize = _size + strlen(str);
if (_capacity - 1 < totalSize + 1)
reserve(totalSize);
size_t k = 0;
for (size_t i = _size; i < totalSize; ++i)
_str[i] = str[k++];
_size = totalSize;
_str[_size] = '\0';
return *this;
}
what::string& what::string::operator+=(char c)
{
size_t totalSize = _size + 1;
if (_capacity - 1 < totalSize + 1)
reserve(totalSize);
_str[_size] = c;
_size = totalSize;
_str[_size] = '\0';
return *this;
}
what::string& what::string::append(const what::string& str)
{
*this += str;
return *this;
}
what::string& what::string::append(const char* str, size_t n)
{
assert(n <= strlen(str));
for (size_t i = 0; i < n; ++i)
*this += str[i];
*this += '\0';
return *this;
}
// 有了 += 的功能,剩下的 append 很好实现,自己试试咯
void what::string::push_back(char c)
{
*this += c;
}
void what::string::swap(string& str)
{
std::swap(_str, str._str);
std::swap(_size, str._size);
std::swap(_capacity, str._capacity);
}
what::string& what::string::insert(size_t pos, const what::string& str)
{
assert(pos <= _size);
size_t len = strlen(str._str);
if (_capacity - 1 < _size + len + 1)
reserve(_size + len + 2);
for (size_t end = _size + len; end > pos + len - 1; --end)
_str[end] = _str[end - len];
strncpy(_str + pos, str._str, len);
_size += len;
return *this;
}
what::string& what::string::erase(size_t pos, size_t len)
{
assert(len != 0 && pos < _size);
if (len == npos || len >= _size - pos + 1)
{
_size = pos;
_str[_size] = '\0';
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
// String operations: ************************************
const char* what::string::c_str() const
{
return _str;
}
const char* what::string::data() const
{
return _str;
}
size_t what::string::copy(char* s, size_t len, size_t pos) const
{
assert(pos < _size);
if (len + pos >= _size)
{
strncpy(s, _str + pos, _size - pos);
return _size - pos;
}
else
{
strncpy(s, _str + pos, len);
return len;
}
}
size_t what::string::find(char c, size_t pos) const
{
assert(pos < _size);
for (size_t i = pos; i < _size; ++i)
if (_str[i] == c)
return i;
return npos;
}
size_t what::string::find(const char* s, size_t pos) const
{
assert(pos < _size);
const char* p = strstr(_str + pos, s);
if (p)
return p - _str;
else
return npos;
}
what::string what::string::substr(size_t pos, size_t len) const
{
assert(pos < _size);
char buff[128];
string tmp;
buff[127] = '\0';
if (len >= _size - pos)
{
while (true)
{
size_t num = copy(buff, 127, pos);
if (num != 127)
{
buff[num] = '\0';
tmp += buff;
break;
}
else
{
pos += 127;
tmp += buff;
}
}
}
else
{
while (true)
{
if (len >= 127)
{
size_t num = copy(buff, 127, pos);
tmp += buff;
pos += 127;
len -= 127;
}
else
{
size_t num = copy(buff, len, pos);
buff[len] = '\0';
tmp += buff;
break;
}
}
}
return tmp;
}
// Non-member function overloads: *******************************************
what::string what::operator+(const what::string& lhs, const what::string& rhs)
{
what::string ret;
ret += lhs;
ret += rhs;
return ret;
}
bool what::operator==(const what::string& lhs, const what::string& rhs)
{
int ret = strcmp(lhs.c_str(), rhs.c_str());
return ret == 0;
}
bool what::operator!=(const what::string& lhs, const what::string& rhs)
{
return !(lhs == rhs);
}
bool what::operator<(const what::string& lhs, const what::string& rhs)
{
int ret = strcmp(lhs.c_str(), rhs.c_str());
return ret < 0;
}
bool what::operator<=(const what::string& lhs, const what::string& rhs)
{
return (lhs < rhs) || (lhs == rhs);
}
bool what::operator>(const what::string& lhs, const what::string& rhs)
{
return !(lhs <= rhs);
}
bool what::operator>=(const what::string& lhs, const what::string& rhs)
{
return !(lhs < rhs);
}
void what::swap(what::string& x, what::string& y)
{
x.swap(y);
}
std::istream& what::operator>>(std::istream& is, what::string& str)
{
str.clear();
size_t i = 0;
char c = '\0';
char buff[128] = { 0 };
c = is.get();
while (c != ' ' && c != '\n')
{
buff[i++] = c;
if (i == 127)
{
buff[i] = '\0';
str += buff;
i = 0;
}
c = is.get();
}
if (i > 0)
{
buff[i] = '\0';
str += buff;
}
return is;
}
std::ostream& what::operator<<(std::ostream& os, const what::string& str)
{
os << str.c_str();
return os;
}
std::istream& what::getline(std::istream& is, what::string& str, char delim)
{
str.clear();
size_t i = 0;
char c = '\0';
char buff[128] = { 0 };
c = is.get();
while (c != delim)
{
buff[i++] = c;
if (i == 127)
{
buff[i] = '\0';
str += buff;
i = 0;
}
c = is.get();
}
if (i > 0)
{
buff[i] = '\0';
str += buff;
}
return is;
}