#include //用于标准库中的STL containers
分配器顾名思义,分配空间内存。
在C++中,分配单个对象时,通常希望将内存分配和对象初始化组合在一起。一个对象的内存配置和释放(new、delete)一般都包含以下步骤:
当分配一大块内存时,我们通常计划在这块内存上按需构造对象。在此情况下,我们希望将内存分配和对象构造分离。这意味着我们可以分配大块内存,但只在真正需要时才真正执行对象的创建操作(同时付出一定开销)。一般情况下,将内存分配和对象构造组合在一起可能会导致不必要的浪费。
举例:
auto p = new string[100];
for (int i = 0; i < 5; ++i){
p[i] = "balaba...";
}
只需要5个string,而new把100个对象全部构造好了(每个string已经被初始化为空字符串,也就是""),也就是前面将p[0-4]赋值为空字符串的操作,变得毫无意义。
程序实现
template<class T>
class allocator
{
public:
// 1、为什么需要下面这些成员,有什么作用呢?
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type; // size_t是无符号整数
// ptrdiff_t是有符号整数,代表指针相减结果的类型
typedef ptrdiff_t difference_type;
// 2、这是做什么用的,为何template是U,而不是与allocator的T一致?
template<class U>
struct rebind
{
typedef allocator<U> other;
};
// 默认构造函数,什么都不做
allocator() noexcept
{
}
// 泛化的构造函数,也什么都不做
// 3、为什么需要这个泛化的构造函数,不同类型的allocator复制合适吗?
template<class U>
allocator(const allocator<U>&) noexcept
{
}
// 析构函数,什么都不做
~allocator() noexcept
{
}
// 返回对象地址
pointer address(reference val) const noexcept
{
//non-const版调用const版,参见《Effective C++》条款3
return const_cast<reference>(address(static_cast<const_reference>(val)));
}
// 返回对象地址
// reference => T& const_reference => const T&
const_pointer address(const_reference val) const noexcept
{
return &val;
}
// 申请内存,count是指对象个数,不是字节数。
// 4、hint是做什么的?
pointer allocate(size_type count, allocator<void>::const_pointer hint = nullptr)
{
return static_cast<pointer>(::operator new(count * sizeof(value_type)));
}
// 释放内存
void deallocate(pointer ptr, size_type count)
{
::operator delete(ptr);
}
// 可配置的最大量(指对象个数,不是字节数)
size_type max_size() const noexcept
{
return (static_cast<size_type>(-1) / sizeof(value_type));
}
// 构造对象,Args是模板参数包,见《C++ Primer》第5版16.4节
template <class U, class... Args>
void construct(U* p, Args&&... args)
{
::new ((void *)p) U(::std::forward<Args>(args)...);
}
// 析构对象
template <class U>
void destroy(U* p)
{
p->~U(); // 原来模板还可以这样用
}
};
// 5、为什么要对void进行特化?
template<>
class allocator<void>
{
public:
typedef void value_type;
typedef void *pointer;
typedef const void *const_pointer;
template <class U> struct rebind
{
typedef allocator<U> other;
};
};
问题解答
For example, given an allocator object al of type A, you can allocate an object of type _Other with the expression:
(例如,给定类型A的分配器对象al,您可以使用以下表达式分配类型为_Other的对象:)
A::rebind<Other>::other(al).allocate(1, (Other *)0)
Or, you can name its pointer type by writing the type:
(可以通过编写以下类型来命名其指针类型:)
A::rebind<Other>::other::pointer
具体例子:一个保存int的列表list,列表存储的对象并不是int本身,而是一个数据结构,它保存了int并且还包含指向前后元素的指针。那么,list
pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
//pointer => T* const_pointer => const T* size_type => size_t
在标准默认allocator,存储块是使用 一次或多次 ::operator new 进行分配,如果他不能分配请求的存储空间,则抛出bad_alloc异常
template <class U, class... Args>
void construct(U* p, Args&&... args);
constructor将其参数转发给相应的构造函数构造U类型的对象,相当于 ::new ((void*) p) U(forward
template <class U>void destroy (U* p);
该函数使用U的析构函数,就像使用下面的代码一样:P->〜U();
void deallocate(pointer p, size_t n);
//https://www.cnblogs.com/SimonKly/p/7819122.html
//#include "CAnimal.h"
#include
#include
using namespace std;
class Animal
{
public:
#if 1 //即使为0,没有默认构造也是可以,
Animal() : num(0)
{
cout << "Animal constructor default" << endl;
}
#endif
Animal(int _num) : num(_num)
{
cout << "Animal constructor param" << endl;
}
~Animal()
{
cout << "Animal destructor" << endl;
}
void show()
{
cout << this->num << endl;
}
private:
int num;
};
int main()
{
allocator<Animal> alloc; //1.
Animal *a = alloc.allocate(5); //2.
//3.
alloc.construct(a, 1);
alloc.construct(a + 1);
alloc.construct(a + 2, 3);
alloc.construct(a + 3);
alloc.construct(a + 4, 5);
//4.
a->show();
(a + 1)->show();
(a + 2)->show();
(a + 3)->show();
(a + 4)->show();
//5.
for (int i = 0; i < 5; i++)
{
alloc.destroy(a + i);
}
//对象销毁之后还可以继续构建,因为构建和内存的分配是分离的
//6.
alloc.deallocate(a, 5);
cin.get();
return 0;
}
1、https://www.cnblogs.com/lsgxeva/p/7689989.html
2、https://blog.csdn.net/qingdujun/article/details/85224771
3、https://blog.csdn.net/wallwind/article/details/22176291
4、https://blog.csdn.net/xiyanggudao/article/details/51543839
5、https://www.cnblogs.com/SimonKly/p/7819122.html
6、《STL源码剖析》