Item 10:注意 allocator 的惯例和限制。
Item 12:不要对 STL 的线程安全性有任何期望。
- Allocator 最初是为了对在16位系统上的 near 和 far 指针内存访问模式进行抽象而加入的(虽然这个尝试失败了),之后 Allocator 被设计成为标准库提供全攻能的内存管理模块。但由于效率问题,标准委员会弱化了 Allocator 的功能。甚至打多数的 container 根本就不使用 allocator,也因此有了:“allocator is weird”。
- 由于标准的限制在实现 allocator 时你必须定义(typedef) allocator<T>::pointer 和 allocator<T>::reference,而且必须定义为 T* 和 T&。
- Allocator 是弱化的对象,标准规定:同一个的类型(T)的所有 allocator<T> 对象必须等价并且其比较函数必须返回真,这就意味着 Allocator 对象不能拥有自己的 data member,所有的数据必须都是 static 的。也就意味着对同一种类型的存储不能有两个堆,这主要是为了,实现 node based container 的 splice 等函数。考虑如下代码:
template<typename T>
class MyAllocator {...};
std::list<Item, MyAllocator<Item> > listA;
std::list<Item, MyAllocator<Item> > listB;
listA.splice(listB.begin(), listB);
class MyAllocator {...};
std::list<Item, MyAllocator<Item> > listA;
std::list<Item, MyAllocator<Item> > listB;
listA.splice(listB.begin(), listB);
- pointer allocator<T>::allocate(size_type numObjects) 的参数是对象的数量,而不是size。返回值是 T*,但是T*并不指向一个T objects,因为T并没有被构造,仅仅是分配了一块内存。在 node based container 中,动态分配的是节点 node<T>,而不是 T object,标准库采用了如下代码来实现这个功能:
template<typename T>
class MyAllocator {
public:
template<typename Node>
struct rebind {
typedef allocator<Node> other;
};
};
Item 11:理解自定义 allocator 的正确用途。
class MyAllocator {
public:
template<typename Node>
struct rebind {
typedef allocator<Node> other;
};
};
- 当需要自定义容器内对象的内存布局时。
- 可用如下方法为同种类型对象创造不同的堆:
class Heap1 {
public:
static void *alloc(...) {...}
static void *dealloc(...) {...}
};
class Heap2 {
public:
static void *alloc(...) {...}
static void *dealloc(...) {...}
};
template<typename T, typename Heap>
class MyAllocator {
public:
pointer allocate(...) {
//use Heap::alloc;
};
void deallocate(...) {
//use Heap::dealloc;
};
};
vector<int, MyAllocator<int, Heap1> > v1;
vector<int, MyAllocator<int, Heap2> > v2;
public:
static void *alloc(...) {...}
static void *dealloc(...) {...}
};
class Heap2 {
public:
static void *alloc(...) {...}
static void *dealloc(...) {...}
};
template<typename T, typename Heap>
class MyAllocator {
public:
pointer allocate(...) {
//use Heap::alloc;
};
void deallocate(...) {
//use Heap::dealloc;
};
};
vector<int, MyAllocator<int, Heap1> > v1;
vector<int, MyAllocator<int, Heap2> > v2;
- 注意上文中 Heap 是类型而不是对象。
Item 12:不要对 STL 的线程安全性有任何期望。
- 在多线程环境中,使用 Lock Object 方法锁定关键代码:
vector<int> v;
{
Lock<vector<int> > lock(v);
//other operation on vector v;
}
{
Lock<vector<int> > lock(v);
//other operation on vector v;
}