Allocator(概念)是对访问、寻址、分配、释放、构造和析构策略的封装。是一个知足特定要求的类。标准库中须要分配释放存储空间的容器都须要一个Allocator,除了std::array。函数
Allocator 须要知足的条件有不少,可是大部分都是可选的,只有几个必须存在的成员。spa
对于表达式Alloc a2 = a1; Alloc a2(a1) 要求执行完毕后a2 == a1,不可抛出异常指针
对于表达式Alloc a2 = std::move(a1); Alloc a2(std::move(a1)); 使用a1构造a2,a2应等于a1的先前值。(C++17 起要求a1的值在构造后不发生改变,而且a1 == a2。)code
标准没有声明他们的存在,可是显然他们应该和上面的构造语义相同。对象
用于map等分配的实际类型不是你传入的allocator的value_type的状况。内存
对于表达式 AllocA a(b),其中b是由AllocA::template rebind得到的类型AllocB的实例,构造a,使得AllocB(a) == b, b == AllocA(a)。ci
对于表达式 AllocA a(b),其中b是由AllocA::template rebind得到的类型AllocB的实例,构造a,使得a == 以前的 AllocA(b)get
其它的可选设施能够在这一页找到,是否实现由 Allocator 的实现逻辑决定 http://en.cppreference.com/w/cpp/concept/Allocatorit
标准推荐经过 std::allocator_traits<Allocator> 来调用 Allocator 的各类方法,及获取其余类型,这个 trait 类提供了 Allocator 中可选成员的默认实现。io
size_type
若是你不想使用默认的std::size_t,能够用这个来自定义size_type类型,固然对应的allocate和deallocate方法的size参数也应该变成这个类型
rebind用来从已有的allocator类型获取一个新的用来分配另外一个类型U的allocator类型
注意,rebind只对有模板参数的allocator可选
allocator_traits的默认实现是用U来替换当前类型的第一个模板参数
分配足够容纳n个对象的连续空间,ptr用做一个hint(好比在ptr地址附近寻找可用内存,用来保持局部性)
获取可分配的最大对象数目
allocator_traits会提供一个返回(size_t)-1的实现(或者(size_t)-1 / sizeof(T),since C++17)
在标准库容器拷贝构造时,由构造函数调用,向源allocator获取一个用来构造新容器的allocator的实例
allocator_traits会提供一个直接返回源容器的allocator自己的实现
在构造函数不可以知足allocator的逻辑需求时定义这个函数
在给定指针指向的内存上构造对象,须要注意的是,ptr指向的对象类型不必定是allocator的value_type,这个函数有必要作成模板的
在须要自定义对象构造行为时定义它,好比打个log,try_catch一下什么的
析构ptr指向的对象,须要注意的是,ptr指向的对象类型也不必定是value_type,这个函数有必要作成模板的
allocator的相等比较的意义是,一个allocator分配的空间,是否能够用另一个allocator来释放,is_always_equal旨在尽量消除运行期的比较
std::allocator就是always_equal的,由于他们都是new和delete的封装,一个std::allocator new的固然能够用另外一个std::allocator来delete
allocator_traits的默认实现是,当你的allocator是空类,那么为true_type
此三个类型标记了在容器进行拷贝赋值、移动赋值或交换的时候,allocator是否须要进行对应操做。
容器在进行拷贝赋值、移动赋值和交换时的逻辑,应该考虑到以上成员和allocator的相等性
在两个容器拷贝赋值时(container1 = container2)
propagate…copy… |
两个allocator是否相等 |
拷贝赋值行为 |
true |
true |
拷贝allocator,拷贝container2全部元素 |
true |
false |
析构container1全部元素并释放空间,拷贝allocator,拷贝container2元素 |
false |
true |
不拷贝allocator,拷贝container2全部元素 |
false |
false |
不拷贝allocator,拷贝container2全部元素 |
在两个容器移动赋值时(container1 = std::move(container2))
propagate…move… |
两个allocator是否相等 |
移动赋值行为 |
true |
true |
析构container1全部元素并释放空间,移动allocator,接管container2的内部指针 |
true |
false |
析构container1全部元素并释放空间,移动allocator,接管container2的内部指针 |
false |
true |
析构container1全部元素并释放空间,不移动allocator,接管container2的内部指针 |
false |
false |
析构container1全部元素,不释放空间,不移动allocator,分配足够装下container2全部元素的空间,将container2的元素尽数移动过来 |
在两个容器交换时,没有更多问题,仅需视propagate_on_container_swap值,交换allocator便可。但须要注意的是,若是allocator不可交换,而且不相等,那么容器交换是UB。
固然以上只是标准容器的实现,你的容器大能够没必要如此麻烦。