vector第三步修炼之道
来源:互联网 发布:linux网络服务器项目 编辑:程序博客网 时间:2024/06/05 00:36
在vector第二步修炼之道中,我们开辟内存都是使用new,释放内存都是delete。在我们使用内置类的时候,看不到区别。如果我们使用自定义类,并且自定义类还比较复杂,那么这种优化就显得很重要了。
new操作符主要干两件事:
(1)申请内存;
(2)初始化
delete 操作符主要干两件事:
(1)释放内存;
(2)析构
那么在上一个篇博客中,我们就看到优化的地方。我们需要将申请内存和初始化分开进行;将析构和释放内存分开进行。
问题:
因此,如何把一个对象的内存开辟和对象构造分开,对象析构和内存释放分开?
解决方案:
内存开辟:operator new(size)
char p = (char)operator new(size);
在一个已经开辟好的内存上构造对象:定位new
A *pa = new (p) A();
对象的析构和内存释放分开
析构:pa->~A();
释放内存:operator delete(pa);
在STL 库中,有自定义的配置器:allocator。我看了下STL库中的源码:
#ifdef __STL_USE_STD_ALLOCATORStemplate <class _Tp>class allocator { typedef alloc _Alloc; // The underlying allocator.public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; typedef const _Tp& const_reference; typedef _Tp value_type; template <class _Tp1> struct rebind { typedef allocator<_Tp1> other; }; allocator() __STL_NOTHROW {} allocator(const allocator&) __STL_NOTHROW {} template <class _Tp1> allocator(const allocator<_Tp1>&) __STL_NOTHROW {} ~allocator() __STL_NOTHROW {} pointer address(reference __x) const { return &__x; } const_pointer address(const_reference __x) const { return &__x; } // __n is permitted to be 0. The C++ standard says nothing about what // the return value is when __n == 0. _Tp* allocate(size_type __n, const void* = 0) { return __n != 0 ? static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp))) : 0; //申请空间 } // __p is not permitted to be a null pointer. void deallocate(pointer __p, size_type __n) { _Alloc::deallocate(__p, __n * sizeof(_Tp)); } //回收空间 size_type max_size() const __STL_NOTHROW { return size_t(-1) / sizeof(_Tp); } void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); } //使用定位new构造 void destroy(pointer __p) { __p->~_Tp(); } //析构函数};
static void* allocate(size_t __n) { void* __result = malloc(__n); //底层开辟空间使用malloc if (0 == __result) __result = _S_oom_malloc(__n); return __result; } static void deallocate(void* __p, size_t /* __n */) { free(__p);//底层开辟空间使用free }
根据上述原理,我们也可以自定义空间配置器,专门识别以上四个方法。
定义空间配置器
template<typename T>class myAllocator{public: //allocate : 开辟内存的 malloc ptmalloc T* allocate(size_t size) { return (T*)operator new(sizeof(T)*size); } //deallocate : 释放内存的 free void deallocate(void *p) { operator delete(p); } void construct(T* _P, const T& _V) { new (_P) T(_V); } //destroy : 专门析构的 void destroy(T* _P) { _P->~T(); }};
声明vector模板
template <typename E, typename A = myAllocator<E>>class vector{public: //默认构造函数,所有成员都给默认的零值 vector(int initialsize = 0, const A &a = A()); //vector(int initialsize , const A &a ); //num:初始元素的个数,value表示初始元素的值 vector(int num, E value); //用[first, last)区间的元素初始化当前容器 vector(E *first, E *last); //析构函数 ~vector(); //拷贝构造函数 vector(const vector&src); //赋值运算符的重载函数 void operator=(const vector&src); //向容器的末尾添加新元素value,若增长内存,调用resize函数 void push_back(const E &value); //删除容器末尾的元素 void pop_back(); //查找某个元素的地址 E* getpos(int val); //向指定位置pos插入新元素value,若增长内存,调用resize函数 void insert(E *pos, const E &value); //删除指定位置的元素 void erase(E *pos); //打印容器有效元素值的函数 void show()const; //判断容器是否空 bool empty()const; //判断容器是否满 bool full()const;private: //内存增长函数,按原有容量的两倍增长 void resize() { if (_end == 0)//默认构造vector; { _end = 1; _first = _allocator.allocate(_end); } else { E *_newfirst = _allocator.allocate(_end*2); for (int i = 0; i < _end; i++) { _allocator.construct(_newfirst + i, _first[i]); _allocator.destroy(_first + i); } _end *= 2; _allocator.deallocate(_first); _first = _newfirst; } } A _allocator;//存储用户指定的空间配置器 E *_first; //存储放入容器的元素 int _end; //_element数组的总容量 int _last; //_element有效元素的个数};
实现方法
//默认构造函数,所有成员都给默认的零值template <typename E,typename A= myAllocator<E>>vector<E,A>::vector(int initialsize = 0,const A &a=A()) :_last(0),_end(initialsize),_allocator(a){ if (initialsize == 0) { _first = NULL; } else { _first = _allocator.allocate(_end); }}//num:初始元素的个数,value表示初始元素的值template <typename E, typename A = myAllocator<E>>vector<E,A>::vector(int num, E value) :_end(num), _last(num){ _first = _allocator.allocate(num); for (int i = 0; i < _end; i++) { _allocator.construct(_first+i,value); }}////用[first, last)区间的元素初始化当前容器template <typename E, typename A = myAllocator<E>>vector<E, A>::vector(E *first, E *last){ int size = *last - *first; _first = _allocator.allocate(size); _end = _last = size; for (int i = 0; i < size; i++) { _allocator.construct(_first + i, (*first)++); }}//析构函数template <typename E, typename A = myAllocator<E>>vector<E, A>::~vector(){ if (_first != NULL) { for (int i = 0; i < _last; i++) { _allocator.destroy(_first+i); } _allocator.deallocate(_first); _first = NULL; _end = 0; _last = 0; }}//拷贝构造函数template <typename E, typename A = myAllocator<E>>vector<E, A>::vector(const vector &src){ _end = src._end; //_first = new E[_end]; _first = _allocator.allocate(_end); _last = src._last; for (int i = 0; i < _last; i++) { _allocator.construct(_first + i, (src._first)[i]); }}//赋值运算符的重载函数template <typename E, typename A = myAllocator<E>>void vector<E, A>::operator=(const vector &src){ if (this == &src) { return; } if (_first != NULL) { for (int i = 0; i < _last; i++) { _allocator.destroy(_first + i); } _allocator.deallocate(_first); } _end = src._end; _first = _allocator.allocate(_end); _last = src._last; for (int i = 0; i < _last; i++) { _allocator.construct(_first + i, (src._first)[i]); }}//向容器的末尾添加新元素value,若增长内存,调用resize函数template <typename E, typename A = myAllocator<E>>void vector<E, A>::push_back(const E &value){ if (full()) { resize(); } _allocator.construct(_first + _last, value); _last++;}//删除容器末尾的元素template <typename E, typename A = myAllocator<E>>void vector<E, A>::pop_back(){ if (!empty()) { _last--; _allocator.destroy(_first + _last); }}// vector 元素的位置template <typename E, typename A = myAllocator<E>>E* vector<E, A>::getpos(int val){ for (int i = 0; i < _end; i++) { if (_first[i] == val) { return &(_first[i]); } } return NULL;}//向指定位置pos插入新元素value,若增长内存,调用resize函数template <typename E, typename A = myAllocator<E>>void vector<E, A>::insert(E *pos, const E &value){ int index = pos - _first; if (index<0 || index>_last) { printf("error"); return; } if (full()) { resize(); } if (index < _last) { for (int i = _last; i > index; --i) { _allocator.construct(_first + i, _first[i - 1]); _allocator.destroy(_first + i-1); } } _allocator.destroy(_first + index); _allocator.construct(_first + index, value); _last++;}//删除指定位置的元素template <typename E, typename A = myAllocator<E>>void vector<E, A>::erase(E *pos){ int index = pos - _first; if (index<0 || index>_last) { printf("error"); return; } if (!empty()) { for (int i = index; i < _last-1; i++) { _allocator.destroy(_first + i); _allocator.construct(_first + i, _first[i + 1]); } _last--; _allocator.destroy(_first + _last); }}//打印容器有效元素值的函数template <typename E, typename A = myAllocator<E>>void vector<E, A>::show()const{ if (_first != NULL) { for (int i = 0; i < _last; i++) { cout << _first[i]; } cout << endl; }}//判断容器是否空template <typename E, typename A = myAllocator<E>>bool vector<E, A>::empty()const{ if (_last == 0) { return true; } else { return false; }}//判断容器是否满template <typename E, typename A = myAllocator<E>>bool vector<E, A>::full()const{ if (_last == _end) { return true; } else { return false; }}
测试函数
#include<iostream>#include "vectorAllocate.h"using namespace std;int main(){ myAllocator<int> alloc; vector<int, myAllocator<int>> vec1(10, alloc); vec1.show(); vector<int, myAllocator<int>> vec2(10, 1); vec2.show(); int m = 3; int n = 8; vector<int, myAllocator<int>> vec3(&m, &n); vec3.show(); vector<int, myAllocator<int>> vec4(vec3); vec4.show(); vector<int, myAllocator<int>> vec5=vec4; vec5.show(); vec5.push_back(10); vec5.show(); vec5.pop_back(); vec5.show(); if (vec5.getpos(3)!=NULL) { vec5.insert(vec5.getpos(3),0); } vec5.show(); if (vec5.getpos(7) != NULL) { vec5.erase(vec5.getpos(7)); } vec5.show(); return 0;}
总体实现方法和《vector第二步修炼之道》大同小异,只是申请空间时换成空间配置器的operator new,构造是定位new,然后回收空间时operator delete,最后析构。
总结:多看源码,多分析,最后可以造出属于自己的小轮子。
阅读全文
0 0
- vector第三步修炼之道
- vector第二步修炼之道
- vector第四步修炼之道
- vector第一步修炼之道
- CSS网站布局十步之第三步
- fedora晋级初步之第三步文件系统
- java入门第三步之数据库连接
- 程序员修炼之道
- 程序员修炼之道
- [原创]修炼之道
- 程序员修炼之道
- 程序员修炼之道
- 程序员修炼之道
- 程序员修炼之道
- 程序员修炼之道
- 程序员修炼之道
- 程序员修炼之道
- 修炼之道
- java工厂模式
- MongoDB必知必会
- caffe-MathFunction
- [Linux] CentOS关闭防火墙
- Python3与OpenCV3.3 图像处理(十七)--图像梯度
- vector第三步修炼之道
- 15分钟实战机器学习:验证码(CAPTCHA)识别
- 如何使用阿里云群发短信
- 工业相机标定的相关知识
- Spring cache
- 【Django】简析Django的模板系统发展史
- eclipse配置tomcat运行时访问路径不需要项目名称
- hashcode和equals为什么都要重写?
- ASP.net C# Label 英文被隔断问题