实现一个简单的STL容器 --> vector
- 实现了容器容器的空间配置器,迭代器,和基本函数方法。
#include <iostream>
using namespace std;
// 空间配置器
template <typename T>
struct Myallocator
{
T* allocate(size_t size) // 开辟内存
{
return (T*)malloc(size * sizeof(T));
}
void deallocate(void* p) // 释放内存
{
free(p);
}
void construct(T* p,const T&val) // 负责构造对象
{
new(p)T(val); // 定位new
}
void destroy(T* p) // 析构对象
{
p->~T();
}
};
template<typename T,typename ALLoc = Myallocator<T>>
class Myvector
{
public:
Myvector(int size = 1)
{
mfirst = malloc.allocate(size); // 开辟数组
mlast = mfirst;
mend = mfirst + size;
}
~Myvector()
{
for (T* p = mfirst; p != mlast; ++p)
{
malloc.destroy(p); // 析构对象
}
malloc.deallocate(mfirst); // 释放内存
mfirst = nullptr;
mlast = nullptr;
mend = nullptr;
}
// 拷贝构造函数
Myvector(const Myvector<T> & mvec)
{
// 开辟内存
size_t size = mvec.mend - mvec.mfirst;
mfirst = malloc.allocate(size);
// 移动元素
size_t len = mvec.mlast - mvec.mfirst;
for (int i = 0; i < len; ++i)
{
malloc.construct(mfirst + i, mvec.mfirst[i]);
}
mlast = mfirst + len;
mend = mfirst + size;
}
// 赋值运算符重载函数
Myvector<T>& operator =(const Myvector<T> & mvec)
{
if (&mvec == this)
return *this;
// 先释放析构原来的对象,释放原来的内存
if (mfirst != nullptr)
{
// 析构对象
for (T*p = mfirst; p != mlast; ++p)
{
malloc.destroy(p);
}
// 释放内存
malloc.deallocate(mfirst);
}
// 开辟内存
size_t size = mvec.mend - mvec.mfirst;
mfirst = malloc.allocate(size);
// 移动元素
size_t len = mvec.mlast - mvec.mfirst;
for (int i = 0; i < len; ++i)
{
malloc.construct(mfirst + i, mvec.mfirst[i]);
}
mlast = mfirst + len;
mend = mfirst + size;
return *this;
}
// 右值引用的拷贝构造
Myvector(Myvector<T> && mvec)
{
mfirst = mvec.mfirst;
mlast = mvec.mlast;
mend = mvec.mend;
mvec.mfirst = mvec.mlast = mvec.mend = nullptr;
}
// 右值引用的赋值运算符函数
Myvector<T>& operator =(Myvector<T> && mvec)
{
if (&mvec == this)return *this;
mfirst = mvec.mfirst;
mlast = mvec.mlast;
mend = mvec.mend;
mvec.mfirst = mvec.mlast = mvec.mend = nullptr;
return *this;
}
// 尾部插入元素
void push_back(const T & val)
{
if (full())
{
expand(); // 扩容
}
else
{
malloc.construct(mlast, val);
mlast++;
}
}
void pop_back()
{
if (empty())
{
return;
}
mlast--;
malloc.destroy(mlast);
}
bool full()const { return mlast == mend; }
bool empty()const { return mfirst == mlast; }
size_t size()const { return mlast - mfirst; }
// 中括号运算符重载函数
T& operator[](size_t index)const
{
if ((index < 0) || (index > (mlast - mfirst)))
throw "index not use";
return mfirst[index];
}
T& back()const
{
if (empty())
throw"vector is empty";
return (*(mlast - 1));
}
T& front()const
{
if (empty())
throw"vector is empty";
return (*mfirst);
}
/实现嵌套iterator迭代器//
class Myiterator
{
public:
Myiterator(T*p = nullptr):ptr(p){}
T& operator *()const { return *ptr; }
T* operator->()const { return ptr; }
bool operator !=(const Myiterator& val)const { return ptr != val.ptr; }
void operator ++(int) { ptr++; }
void operator ++() { ++ptr; }
private:
T * ptr;
};
/
Myiterator begin() { return Myiterator(mfirst); }
Myiterator end() { return Myiterator(mlast); }
private:
T* mfirst; // 指向内存起始地址
T* mlast; // 指向最后一个元素的后继位置
T* mend; // 指向内存的末尾位置。
ALLoc malloc; // 容器空间配置器
// 扩容 2倍方式扩容
void expand()
{
// 开辟内存
size_t len = mend - mfirst;
size_t size = len * 2;
T * tmp = malloc.allocate(size);
// 移动元素
for (int i = 0; i < len; ++i)
{
malloc.construct(tmp + i, mfirst[i]);
}
// 析构原内存元素
for (T* p = mfirst; p != mend; ++p)
{
malloc.destroy(p);
}
// 释放内存
malloc.deallocate(mfirst);
mfirst = tmp;
mlast = mfirst + len;
mend = mfirst + size;
}
};
int main()
{
Myvector<int> vec;
for (int i = 0; i < 10; ++i)
{
vec.push_back(rand() % 100);
}
for (int i = 0; i < vec.size(); ++i)
{
cout << vec[i] << " ";
}
cout << endl;
Myvector<int>::Myiterator it = vec.begin();
// auto it = vec.begin()
for (; it != vec.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
for (int val : vec)
{
cout << val << " ";
}
cout << endl;
cout << vec.back() << endl;
cout << vec.front() << endl;
}
- 容器的空间配置器主要是开辟内存和构造对象分开,因为new默认是开辟内存并调用构造函数。
- 迭代器一般是容器的嵌套类,STL提供的迭代器种类有四种,正向迭代器、反向迭代器、正向const迭代器,反向const迭代器,这里只是实现正向的。
- 另外实现的带右值引用的拷贝构造和赋值运算符重载函数,右值引用是C++11以后实现的,右值引用的拷贝构造和赋值运算符函数会自动匹配临时对象的拷贝或者赋值,直接将资源转移,因为临时对象在拷贝或赋值完成后就会直接释放掉自己资源,那不如直接将资源转移,这样可以提高效率。
新手上路,如有错误,请指出!!!