在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_ALLOCATORS
template <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,最后析构。
总结:多看源码,多分析,最后可以造出属于自己的小轮子。