vector的实现,说说大体框架吧。
1.vector中通过静态私有allotor的对象来动态实时分配空间。
每次插入新内容是,都会检测空间是否足够,不够的话,重现分配现在大小的两倍,将内容拷贝过去。杀掉旧的空间。修改vector指针成员。这里有一点注意到是,类的静态成员要在类外进行定义,不然会报无法解析的外部符号错误。因此,在.cpp文件开头中有allocator<string>like_vector::alloc;
2.iterator用嵌套类实现。
嵌套类内,可以访问外层类的私有成员,而外层类不能访问嵌套类的私有成员。
这里为什么用嵌套类呢,主要是标准中的iterator定义的时候是vector<string>::iterator a;
所以呢,我也这样模仿,让iterator作为vector内部的类。
3.然后剩余的就是vector中基本功能的实现了。
程序如下:
.h文件:
#ifndef PCH_H
#define PCH_H
#include<memory>
#include<string>
//这个头文件实际是没有必要的,这里只是为了测试free函数用的
#include<iostream>
using namespace std;
// vector简单版实现
class like_vector {
public:
//迭代器(内部嵌套类)
class iterator;
like_vector():
first_element(nullptr),first_free(nullptr),tail(nullptr){}
//拷贝构造函数
like_vector(const like_vector&);
//拷贝复制函数
like_vector& operator =(const like_vector&);
//析构函数
~like_vector();
//返回实际使用空间大小,以string为单位
int size()const;
//返回所有分配空间的大小,以string为单位
int capacity()const;
iterator begin() const;
iterator end() const;
//在尾部插入一个string元素
void push_back(const string&);
private:
//通过alloc对象来分配内存空间(所有vector<string>的对象都公用这一个alloc对象)
static allocator<string> alloc;
//指向内存首地址的指针
string* first_element;
//指向第一个未用内存地址的指针
string* first_free;
//指向内存空间最后一个内存空间后面的地址的指针
string* tail;
//检查空间是否够用
void check_n_alloc();
//重新分配空间并且将就内容复制
void rellocate();
//回收空间
void free();
};
class like_vector::iterator {
public:
iterator(string* a=nullptr):
ptr(a){}
//拷贝复制函数
iterator& operator =(const iterator& a)
{ ptr = a.ptr; return *this; }
//*运算符
string& operator *() {
return *ptr;
}
//->运算符
string* operator ->() {
return ptr;
}
//这里++运算符仅适用于前置++哦
iterator& operator ++() {
++ptr;
return *this;
}
bool operator !=(const iterator& a) {
return (ptr != a.ptr);
}
iterator operator +(int a) {
ptr += a;
return *this;
}
iterator operator -(int a) {
ptr -= a;
return *this;
}
private:
string* ptr;
};
#endif
/*最重要的是分配空间,这里呢是通过对malloc和free函数封装的类allocteor完成的,做为成员变量
还需要一个嵌套迭代器类,然后们能够返回相应的地带其,
最后就是提供的操作了*/
/*总结:
对于出现无法解析的外部符号的问题,一般的三种错误
1.未添加头文件
2.未添加相应的库文件。好吧,这个暂时我还不太清楚
3.这个应该是这次犯的错误,类中定义的静态成员变量没有在类外进行初始化
*/
.cpp文件:
#include "pch.h"
//这里要把静态成员变量给重新定义一下,不然会报无法解析的外部符号错误
allocator<string>like_vector::alloc;
//拷贝构造函数
like_vector::like_vector(const like_vector& a) {
//1.分配足够大的空间
first_element=alloc.allocate(a.capacity());
//2.将内容拷贝过来
auto copy_first_element = first_element;
auto a_copy_first_element = a.first_element; //参数为const,我们只能用变量结束a.first_element,然后遍历++
for (size_t i = 0; i != a.size(); ++i)
alloc.construct(copy_first_element++, *a_copy_first_element++);
//3.修改成员
first_free = first_element + a.size();
tail = first_element + a.capacity();
}
//拷贝复制函数
like_vector& like_vector::operator =(const like_vector& a) {
//1.分配足够大的空间
auto recieve_first_element = alloc.allocate(a.capacity());
//2.将内容进行拷贝
auto copy_recieve_first_element = recieve_first_element;
auto a_copy_first_element = a.first_element;
for (size_t i = 0; i != a.size(); ++i)
alloc.construct(copy_recieve_first_element++, *a_copy_first_element++);
//3.杀掉原本的空间
free();
//4.修改成员
first_element = recieve_first_element;
first_free = first_element + a.size();
tail = first_element + a.capacity();
return *this;
}
//析构函数
like_vector::~like_vector() {
free();
}
int like_vector::size()const {
//这里就算是指针为nullptr也是可以进行-操作的,但是呢,不能*和->操作
return first_free - first_element;
}
int like_vector::capacity()const {
return tail - first_element;
}
//这里我们返回临时对象就可以
like_vector::iterator like_vector::begin()const {
return iterator(first_element);
}
like_vector::iterator like_vector::end()const {
return iterator(first_free);
}
void like_vector::push_back(const string& a) {
//1.查看空间是否足够
check_n_alloc();
//2.插入新内容
alloc.construct(first_free++, a);
}
//检查空间是否足够
void like_vector::check_n_alloc() {
if (first_free == tail)
rellocate();
}
//当空间不够时重新分配空间
void like_vector::rellocate() {
//1.分配更多的空间
//如果size()为0则分配1个空间,如果不为0,则分配二倍空间
auto newcapacity = size() ? 2 * size() : 1;
auto newdata = alloc.allocate(newcapacity); //这里返回的newdata是一个void类型的指针
//2.将就内容复制过去
auto size_length = size(); //将原来的有数据长度保存
auto dest = newdata;
auto elem = first_element;
if (elem != nullptr) {
for (size_t i = 0; i != size(); ++i)
//consturct函数第一个参数接受一个指向动态分配内存的string类型的指针,第二个参数做初始化的量,将这个量传递给构造函数进行
//初始化
alloc.construct(dest++, *elem++);
//3.删除掉旧的空间
free();//我们自己定义的函数哦,不是标准库中的那个free函数
}
//4.更新类中的成员变量
first_element = newdata;
first_free = first_element + size_length;
tail = first_element + newcapacity;
}
void like_vector::free() {
//1.销毁掉内部数据
if (first_element) {
for (auto p = first_element; p != first_free; ++p) {
cout << "杀掉" << endl;
alloc.destroy(p);//这里destroy函数会调用string的析构函数,来释放器分配的动态内存
}
}
//2.归还空间
alloc.deallocate(first_element, tail - first_element);
}
main文件测试程序:
#include "pch.h"
#include <iostream>
using namespace std;
int main()
{
like_vector a;
//测试push_back以及世界分配的内存大小
cout << a.size() << endl;
cout << a.capacity() << endl;
a.push_back("xiaoming");
cout << a.size() << endl;
cout << a.capacity() << endl;
cout << *a.begin() << endl;
a.push_back("luo");
cout << a.size() << endl;
cout << a.capacity() << endl;
cout << *(++a.begin()) << endl;
a.push_back("hello");
cout << a.size() << endl;
cout << a.capacity() << endl;
cout << *(a.begin()+2) << endl;
a.push_back("tomorrow");
cout << a.size() << endl;
cout << a.capacity() << endl;
cout << *(a.begin()+3) << endl;
a.push_back("happy");
cout << a.size() << endl;
cout << a.capacity() << endl;
cout << *(a.begin()+4) << endl;
/*到这一步之前,我们可以看到我们push_back的内容确实写到了实际的存储空间中,并且嵌套类迭代器也是可用的*/
//这里难道是end()函数除了错误吗?
for (auto b = a.begin(); b != a.end(); ++b) {
cout << *b << endl;
}
//测试拷贝构造函数
like_vector b(a);
cout << b.size() << endl;
cout << b.capacity() << endl;
for (auto a = b.begin(); a!= b.end(); ++a)
cout << *a << endl;
//测试拷贝复制函数
like_vector c;
c = b;
cout << c.size() << endl;
cout << c.capacity() << endl;
for (auto a = c.begin(); a != c.end(); ++a) {
cout << *a << endl;
}
}
执行结果如下: