string的模拟实现
简述:模拟实现中,复现了文档里面的运算符重载,完成了iterator(迭代器)的实现,完成了字符(以及字符串)查找和插入,实现基本的拷贝构造,赋值重载。
对自己实现过程中遇见的问题做出几个标记。
名字都保证和C++标准网站的命名一致,实现相同或者相类似的功能。
reserve:这个函数的任务是扩容,参考g++编译器下面的实现,我也用了二倍扩容的方法,这里需要注意多留下一个空间方便放’\0’;
void reserve(size_t n)
{
_capacity= _capacity==0 ? 4:_capacity*2;//_capacity是容量,指容纳的有效字符个数
while(n>_capacity)
{
_capacity*=2;
}
char* t = new char[_capacity+1];//存n+1放下\0
strcpy(t,_str);//会拷贝\0给
delete []_str;
_str = t;
}
[](下标解引用运算符)的重载
:这个基本上值得注意的不多,就是实现两个,方便外面传const型的string时,里面因权限延展的报错。
char& operator[](size_t pos)
{
assert(pos<_size);
return _str[pos];
}
const char& operator[](size_t pos)const
{
assert(pos<_size);
return _str[pos];
}
swap
:算法库里面实现的需要拷贝一次临时对象,消耗太大(调用赋值拷贝那些),根据底层,我们就可以自己写一个。
只需要交换底层的指针和内部变量就可以了。
void swap(string & s)
{
std::swap(_str,s._str);
std::swap(_capacity,s._capacity);
std::swap(_size,s._size);
}
= 赋值运算符重载
:再有了基本的构造函数和交换内存之后,这就变得很简单,新建一个tmp,交换内部的内容即可。
string& operator=(const string& s)
{
if(this != &s)
{
string tmp(s._str);//传一个字符串去构造,也可以直接调用拷贝构造
swap(tmp);//交换内存就完成了。
}
return *this;
}
拷贝构造
:拷贝构造就是类似的道理
string(const string& s)
:_size(0),
_capacity(0),
_str(new char[1]{0})
{
string tmp(s._str);
swap(tmp);
}
<< (流插入) >> (流提取)的运算符重载
:首先整个函数是在类外面实现的,原因是在类里面的话只能、string s; s<<cout;
这种写法就很奇怪,为了符合习惯(或者说是规范),因此我们就只能在外面重载。
ostream& operator<<(ostream& out,const string& s)
{
for(int i=0;i<s.size();i++)
{
out<<s[i];
}
return out;
}
istream& operator>>(istream& in,string& s)
{
// s.clear();
// char t = 0;
// t = in.get();
// while(t!=' ' && t!= '\n')//涉及多次重扩展内存
// {
// s.push_back(t);
// t = in.get();
// }
// return in;
//利用缓冲区的思维
s.clear();
char arr[256];
size_t i =0;
char ch = in.get();
while(ch != ' ' && ch!= '\n')
{
arr[i++] = ch;
if(i == 255)
{
arr[i] = 0;
s += arr;
i = 0;
}
ch = in.get();
}
arr[i] = 0;
s += arr;
return in;
}
iterator(迭代器)
:因为底层就是连续的物理空间,直接以指针作为迭代器即可。
iterator begin()
{
return _str;
}
iterator end()
{
return _str+_size;
}
iterator begin()const//对应const string 的迭代器
{
return _str;
}
iterator end()const
{
return _str+_size;
}
vector
vector基本类似,是以三个指针去实现的,但是在构造函数的模板处有些不同。
以下两个构造函数,在是vector<int> a(10,0);
就会报错,原因是10,和0都是整形,显然更适合的是模板那个函数。
因此为了解决这一点,加上第三份函数基本就没问题了。
template <class Inputiterator>//放入的迭代器区间。
vector(Inputiterator first,Inputiterator end)
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{
while(first<end)
{
push_back(*first++);
}
}
vector(size_t n,const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{
while(size()<n)
{
push_back(val);
}
}
vector(int n,const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{
while(size()<n)
{
push_back(val);
}
}
reserve
这里扩容需要拷贝原数据,不要直接用memcpy,不然就是在传string就会造成对空间的浅拷贝。
void reserve(size_t n)
{
if(n>capacity())
{
size_t _capacity = n;
T* tmp = new T[_capacity];
int _size = size();
if(_start)
{
copy(tmp,_start,_finish -_start);
delete[]_start;
}
_start = tmp;
_finish = _start+_size;
_endOfStorage = _start +_capacity;
}
}
void copy(iterator dest,const iterator& sor,size_t n)
{
for(int i = 0;i<n;i++)
{
dest[i] = sor[i];
}
}
list
知道了底层双向链表的规律,整日实现是比较简单的。
这里说下迭代器的封装。
//前置声明
template <typename T>
class list;
//迭代器里面需要链表类,链表类需要迭代器,双向依赖
//解决:前置声明:在两个之前,声明后面个类。
//告诉编译器有这个类模板
template<typename T, typename Ref, typename Ptr>
struct __list_iterator//迭代器
{
public:
friend class list<T>;//在模板类A里面声明另外一个模板类B作为友元类,需要在该模板类A前面声明(如果B有定义在A后面的需求)或者定义模板类B才行
//原因就是编译器找类的时候是自下而上的。
typedef list_node<T> Node;
typedef __list_iterator<T, Ref, Ptr> self;
//这里以建立一个模板类,里面实现基本的list迭代器操作。
__list_iterator()
:tmp(nullptr)
{
}
__list_iterator(Node* val)
:tmp(val)
{
}
Ref operator*()
{
return tmp->_data;
}
Ptr operator->()const
{
return &(tmp->_data);
}
self& operator++()
{
tmp = tmp->_next;
return *this;
}
self operator++(int)//后置
{
self t_iterator = *this;
tmp = tmp->_next;
return t_iterator;
}
self& operator--()
{
tmp = tmp->_prev;
return *this;
}
self operator--(int)//后置
{
self t_iterator = *this;
tmp = tmp->_prev;
return t_iterator ;
}
bool operator!=(const self& it_2)
{
return tmp != it_2.tmp;
}
bool operator==(const self & it_2)
{
return tmp == it_2.tmp;
}
private:
Node* tmp;
};
template <class T>
class list
{
typedef list_node<T> Node;
public:
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
typedef __reverse_iterator<T, T&, T*> reverse_iterator;
typedef __reverse_iterator<T, const T&, const T*> const_reverse_iterator;
iterator begin()
{
return _head->_next;//隐式类型转换
}
iterator end()
{
return _head;//隐式类型转换
}
const_iterator begin()const
{
return _head->_next;//隐式类型转换
}
const_iterator end()const
{
return _head;//隐式类型转换
}
reverse_iterator rbegin()
{
return _head->_prev;//隐式类型转换
}
reverse_iterator rend()
{
return _head;//隐式类型转换
}
const_reverse_iterator rbegin()const
{
return _head->_prev;//隐式类型转换
}
const_reverse_iterator rend()const
{
return _head;//隐式类型转换
}
*list()
{
empty_list();
}
template <class InputIterator>
list(InputIterator first, InputIterator last)
{
empty_list();
insert(end(),first,last);
}
list(size_t n,const T& val = T())
{
empty_list();
while(n--!=0)
{
push_back(val);
}
}
list(int n,const T& val = T())
{
empty_list();
while(n--!=0)
{
push_back(val);
}
}
list(const list& val)
{
empty_list();
insert(end(),val.begin(),val.end());
}
~list()
{
clear();
delete _head;
}
void swap(list & t)
{
Node* tt = t._head;
t._head = _head;
_head = tt;
}
void empty_list()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
list& operator=(const list& val)
{
clear();
insert(end(),val.begin(),val.end());
return *this;
}
void push_back(const T& val)
{
insert(end(),val);
}
void push_front(const T& val)
{
insert(begin(),val);
}
void pop_front()
{
erase(begin());
}
void pop_end()
{
erase(end()--);
}
iterator insert(iterator pos,const T& val = T())
{
Node* prev = pos.tmp->_prev;
Node* cur = pos.tmp;
Node* newnode = new Node;
newnode ->_data = val;
newnode->_next = cur;
newnode->_prev = prev;
prev->_next = newnode;
cur->_prev = newnode;
_size++;
return newnode;
}
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last)
{
while(first != last)
{
position = insert(position,*first++);
position++;
}
}
iterator erase(iterator pos)
{
Node* tmp = pos.tmp;
Node *prev = tmp->_prev;
Node *next = tmp->_next;
delete tmp;
next->_prev = prev;
prev->_next = next;
_size--;
return next;
}
void clear()
{
iterator it = begin();
while(it != end())
{
it = erase(it);
}
}*
private:
Node* _head;
size_t _size = 0;
};
具体实现的代码已上传。