C++ STL 空间适配器
目录:
- 实现简单的Vector
- 容器面临的问题
- 空间适配器介绍
- 带有空间适配器的Vector
一 实现简单Vector
#include<iostream> #include<stdlib.h> #include<string.h> #include<string> #include<unistd.h> #include<atomic> using namespace std; template<typename T> class Vector { public: Vector(int size):cursize(0),maxsize(size) { vec = new T[size]; } ~Vector() { delete []vec; vec = nullptr; } // 拷贝构造 Vector(const Vector<T> &src):cursize(src.cursize),maxsize(src.maxsize) { vec = new T[src.maxsize]; for(int i = 0;i < src.cursize;i++) { vec[i] = src.vec[i]; } } // 赋值构造函数 Vector<T> & operator = (const Vector<T> & src) { if(this == &src) { return *this; } delete []vec; vec = new T[src.maxsize]; cursize = src.cursize; maxsize = src.maxsize; for(int i = 0; i< cursize; i++) { vec[i] = src.vec[i]; } return *this; } // push_back; void push_back(const T &val) { if(cursize == maxsize) { resize(); } vec[cursize++] = val; } // pop_back void pop_back() { if(cursize == 0) { return; } --cursize; } private: T *vec; atomic_int cursize; atomic_int maxsize; void resize() { if(maxsize == 0) { vec = new T[1]; cursize = 0; maxsize = 1; }else { T * tmp = new T[2*maxsize]; for(int i = 0; i < maxsize; i++) { tmp[i] = vec[i]; } delete []vec; maxsize *=2; vec = tmp; } } }; int main() { Vector<int> v(10); cout<<endl; return 0; }
二 容器存在的问题
- 定义容器Vector<int> vec(10) 时,我们希望底层开辟10个整型大小的空间,但是不但在开辟空间的同时,还构造了对象,浪费资源
- 调用pop_back时,我们希望是要删除最后一个元素,但是代码上并没有析构,如果这个对象还占有外部资源,那么就会造成内存泄露
- 当vec 的容器出作用域时,还会存在10次的析构,这些都是不合理的
解决办法:
- 当定义容器的时候,我们只需要开辟内存,不用构造无用的对象
- 当pop_back 时不应该只是-- 操作,而应该调用对象的析构函数,是否释放额外的资源
- 当容器vec 析构时,应该把容器的有效对象进行析构,然后在释放整个容器的内存资源。
三 空间配置器
核心就是把容器的内存开辟和对象构造分开,对象析构和内存释放分开,容器适配器主要提供以下函数
空间配置器的函数 | 功能 |
---|---|
allocate | 负责开辟内存 |
deallocate | 负责释放内存 |
construct | 负责在容器中构造对象 |
destroy | 负责析构对象 |
自定义一个简单的空间适配器
#include<iostream> #include<stdlib.h> #include<string.h> #include<string> #include<unistd.h> using namespace std; template<typename T> class Myallocator { public: // 开辟内存空间 T * allocator(size_t size) { return (T*) malloc(sizeof(T) * size); } // 释放内存空间 void deallocate(void * ptr) { free(ptr); } // 负责对象构造 void construct(T *ptr, const T &val) { new ((void*)ptr) T(val); // 定位new 构造对象 } void destory(T *ptr) { ptr->~T(); // 调用对应的析构函数 } };
四 实现一个带有空间配置器的Vector
#include<iostream> #include<stdlib.h> #include<string.h> #include<string> #include<unistd.h> #include<atomic> using namespace std; template<typename T> class Myallocator { public: // 开辟内存空间 T * allocator(size_t size) { return (T*) malloc(sizeof(T) * size); } // 释放内存空间 void deallocate(void * ptr) { free(ptr); } // 负责对象构造 void construct(T *ptr, const T &val) { new ((void*)ptr) T(val); // 定位new 构造对象 } void destory(T *ptr) { ptr->~T(); // 调用对应的析构函数 } }; template<typename T ,typename allocator = Myallocator<T>> class Vector { public: Vector(int size,const allocator &alloc = allocator()):cursize(0),maxsize(size),myallocator(alloc) { vec = myallocator.allocator(size); } ~Vector() { for(int i =0; i< cursize; i++) { myallocator.destory(vec+i); } myallocator.deallocate(vec); vec = nullptr; } // 拷贝构造 Vector(const Vector<T> &src):cursize(src.cursize),maxsize(src.maxsize),myallocator(src.myallocator) { vec = myallocator.allocator(maxsize); for(int i = 0;i < src.cursize;i++) { myallocator.construct(vec+i,src.vec[i]); } } // 赋值构造函数 Vector<T> & operator = (const Vector<T> & src) { if(this == &src) { return *this; } for (int i = 0; i < cursize; ++i) { myallocator.destory(vec+i); } myallocator.deallocate(vec); cursize = src.cursize; maxsize = src.maxsize; vec = myallocator.allocator(maxsize); for(int i = 0; i< cursize; i++) { myallocator.construct(vec+i,src.vec[i]); } return *this; } // push_back; void push_back(const T &val) { if(cursize == maxsize) { resize(); } myallocator.construct(vec+cursize,val); cursize++; } // pop_back void pop_back() { if(cursize == 0) { return; } --cursize; myallocator.destory(vec+cursize); } private: T *vec; atomic_int cursize; atomic_int maxsize; allocator myallocator; void resize() { if(maxsize == 0) { vec = new T[1]; cursize = 0; maxsize = 1; }else { T * tmp = myallocator.allocator(2*maxsize); for(int i = 0; i < maxsize; i++) { myallocator.construct(tmp+i,vec[i]); } for(int i =0; i < maxsize; i++) { myallocator.destory(vec+i); } myallocator.deallocate(vec); maxsize *=2; vec = tmp; } } }; int main() { Vector<int> v(10); cout<<endl; return 0; }
这样就解决了上面遇到的问题,在allocator 还可以带一个内存池实现