allocator类
C++中,内存分配和对象构造紧密纠缠(new),就像对象析构和回收一样(delete)。如果程序员想接管内存分配,即将内存分配和对象构造分开,对于前者,主要是分配和释放未构造的原始内存;对于后者,主要是在原始内存中构造和撤销对象。
分配和释放未构造的原始内存 两种方法:
- allocator类,提供可感知类型的内存分配;
- 标准库中的opeator new和operator delete,它们分配和释放需要大小的原始、未类型化的内存;
在原始内存中构造和撤销对象 不同方法:
- allocator类定义了名为construct和destroy的成员;
- placement new表达式,接受指向未构造内存的指针;
- 直接调用对象的析构函数来撤销对象;
- 算法uninitialized_fill 和 uninitialized_copy,在目的地构造对象;
C++的STL中定义了很多容器,容器的第二个模板参数通常为allocator类型,标准库中allocator类定义在头文件memory中,用于帮助将内存分配和对象的构造分离开来。它分配的内存是原始的、未构造的。
表达式 | 说明 |
allocator<T> a | 定义了一个名为a的allocator对象,它可以为类型T的对象分配内存 |
a.allocator(n) | 分配一段原始的、未构造的内存,这段内存能保存n个类型为T的对象 |
a.deallocate(p, n) |
释放T*指针p地址开始的内存,这块内存保存了n个类型为T的对象,p必须是一个先前由allocate返回的指针, 且n必须是p创建时所要求的大小,且在调用该函数之前必须销毁在这片内存上创建的对象。 |
a.construct(p, t) | 在T*指针p所指向内存中构造一个新元素。运行T类型的复制构造函数用t初始化该对象 |
a.destory(p) | 运行T*指针p所指向对象的析构函数 |
uninitialized_copy(b,e,b2) |
从迭代器b和e指出的输入范围中拷贝元素到从迭代器b2开始的未构造的原始内存中,该函数在目的地构造元素,而不是给它们复制。 假定由b2指出的目的地足以保存输入范围中元素的副本 |
uninitialized_fill(b,e,t) | 将由迭代器b和e指出的范围中的对象初始化为t的副本,假定该范围是未构造的原始内存,使用复制构造函数构造对象 |
uninitalized_fiil_n(b,e,t,n) | 将由迭代器b和e指出的范围中至多n个对象初始化为t的副本,假定范围至少为n个元素大小,使用复制构造函数构造对象 |
STL都会使用allocator类来为容器分配空间,例如:
#include <memory> template <class T> class Vector { public: Vector(): elements(0), first_free(0), end(0) {} void push_back(const T&); private: static std::allocator<T> alloc; // object to get raw memory void reallocate(); // get more space and copy existing elements T* elements; // pointer to first elment in the array T* first_free; // pointer to first free element in the array T* end; // pointer to one past the end of the array }; template <class T> std::allocator<T> Vector<T>::alloc; template <class T> void Vector<T>::push_back(const T& t) { if (first_free == end) { reallocate(); } alloc.construct(first_free, t); first_free++; } template <class T> void Vector<T>::reallocate() { // compute size of current array and allocate space for twice as many elements std::ptrdiff_t size = first_free - elements; std::ptrdiff_t newcapacity = 2 * (size > 1 ? size : 1); T* newelements = alloc.allocate(newcapacity); std::uninitialized_copy(elements, first_free, newelements); for (T* p = first_free; p != elements; alloc.destroy(--p)); if (elements) { alloc.deallocate(elements, end - elements); } elements = newelements; first_free = elements + size; end = elements + newcapacity; }