容器空间配置器allocator
容器的空间配置器allocator应分开完成:
- 内存开辟
- 内存释放
- 对象构造
- 对象析构
#include<iostream>
using namespace std;
// 容器的空间配置器allocator做四件事情 内存开辟/内存释放 对象构造/对象析构
template<typename T>
struct Allocator
{
T* allocate(size_t size) // 负责内存开辟
{
return (T*)malloc(sizeof(T) * size);
}
void deallocate(void* p) // 负责内存释放
{
free(p);
}
void construct(T* p, const T& val) // 负责对象构造
{
new (p) T(val); // 定位new,调用拷贝构造函数
}
void destroy(T* p) // 负责对象析构
{
p->~T();
}
};
/*
容器底层内存开辟,内存释放,对象构造和析构,都通过allocator空间配置器来实现
*/
template<typename T, typename Alloc = Allocator<T>>
class vector
{
public:
vector(int size = 10)
{
// 需要把内存开辟和对象构造分开处理
// _first = new T[size];
_first = _allocator.allocate(size);
_last = _first;
_end = _first + size;
cout << "vector()" << endl;
}
~vector()
{
// 析构容器有效的元素,然后释放_first指针指向的堆内存
// delete[] _first;
for (T *p = _first; p != _last; ++p) // 把有效的对象析构从_first到_last
{
_allocator.destroy(p);
}
_allocator.deallocate(_first); // 释放内存
_first = _end = _last = nullptr;
}
vector(const vector<T>& rhs)
{
int size = rhs._end - rhs._first;
//_first = new T[size];
_first = _allocator.allocate(size);
int len = rhs._last - rhs._first;
for (int i = 0; i < len; ++i)
{
//_first[i] = rhs._first[i];
_allocator.construct(_first + i, rhs._first[i]);
}
_last = _first + len;
_end = _first + size;
}
vector<T>& operator = (const vector<T>& rhs)
{
if (this == &rhs)
{
return *this;
}
//delete[] _first;
for (T* p = _first; p != _last; ++p) // 把有效的对象析构从_first到_last
{
_allocator.destroy(p);
}
_allocator.deallocate(_first);
int size = rhs._end - rhs._first;
//_first = new T[size];
_first = _allocator.allocate(size);
int len = rhs._last - rhs._first;
for (int i = 0; i < len; ++i)
{
//_first[i] = rhs._first[i];
_allocator.construct(_first + i, rhs._first[i]);
}
_last = _first + len;
_end = _first + size;
return *this;
}
void push_back(const T& val)
{
if (full())
expand();
//*_last++ = val; _last指针指向的内存构造一个值为val的对象
_allocator.construct(_last, val);
_last++;
}
void pop_back()
{
if (empty())
return;
//--_last; 不仅要把_last指针--,还需要析构删除的元素
--_last;
_allocator.destroy(_last);
}
T back() const
{
return *(_last - 1);
}
bool full() const { return _last == _end; }
bool empty() const { return _first == _last; }
int size() const { return _last - _first; }
private:
T* _first;
T* _last;
T* _end;
Alloc _allocator;
void expand()
{
int size = _end - _first;
//T* ptmp = new T[2 * size];
T* ptmp = _allocator.allocate(2 * size);
for (int i = 0; i < size; i++)
{
_allocator.construct(ptmp + i, _first[i]);
//ptmp[i] = _first[i];
}
//delete[] _first;
for (T* p = _first; p != _last; ++p)
{
_allocator.destroy(p);
}
_allocator.deallocate(_first);
_first = ptmp;
_last = _first + size;
_end = _first + 2 * size;
}
};
class Test
{
public:
Test() { cout << "Test()" << endl; }
~Test() { cout << "~Test()" << endl; }
Test(const Test&) { cout << "Test(const Test&)" << endl; }
};
int main()
{
//无alloctor的情况下,定义一个基于Test的容器vector,会自动构造默认长度个Test对象
//析构vec的过程则为delete首对象元素的指针,而应为先析构容器有效对象元素,再释放_first申请的堆内存
vector<Test> vec;
Test t1, t2, t3;
//无alloctor的情况下,push_back(t1)相当于在构造函数已经生成对象元素的情况下,重载=运算符来重新赋值
//应在只开辟内存的情况下,使用拷贝构造添加元素
vec.push_back(t1);
vec.push_back(t1);
vec.push_back(t1);
//无alloctor的情况下,pop_back只是将_last指针回退,如果末尾元素有外部资源(如堆资源),则会在元素对象被=重载覆盖后无法被再次访问,造成永久内存泄露。
//应及时释放对象元素的外部资源并析构元素对象
vec.pop_back();
vec.pop_back();
vec.pop_back();
return 0;
}
标签:容器,last,19,rhs,._,first,allocator,size
From: https://www.cnblogs.com/sio2zyh/p/17977351