How can I write a stateful allocator in C++11,given requirements on copy construction?
基本上,尽管C11标准现在允许有状态的分配器,但是我们仍然要求如果您复制某个分配器,则该副本必须通过==运算符与原始值进行比较.这表明该副本可以安全地释放原始分配的内存,反之亦然.
所以,就这样,这已经禁止一个分配器维护独特的内部状态,比如slab-allocator或内存池或者某些东西.一个解决方案是使用shared_ptr指针到实现的内部状态的习语,以便一些原始Allocator的所有副本使用相同的底层内存池.那不算太糟糕除…
根据上述参考的问题,以及所接受的答案,标准也似乎要求分配者< T>具有与Allocator U的可互操作的复制构造函数,使得:
Allocator<T> alloc1; Allocator<U> alloc2(alloc1); assert(alloc1 == alloc2); // must hold true
所以换句话说,分配器类型必须是可互操作的,而不管不同的模板参数.这意味着如果我使用分配器< T>分配一些内存,则我必须能够使用分配器< U>由原始Allocator T构建的实例.
…这几乎是一个展示 – 阻止任何尝试写一个使用某种大小的内存池的分配器,就像一个simple_segregated_storage池,只能返回基于sizeof(T)的一定大小的块.
但是,这真的是真的吗?
我意识到分配器< T> :: rebind需要可互操作的复制构造函数,所以容器的用户不需要知道say的内部细节,链表的节点类型或某些东西.但是据我所知,standard itself似乎并没有说出任何如此严厉的规定,因为分配者&由分配器T构建必须与原始分配者< T>实例.
标准基本上需要以下语义,其中X是类型分配器< T>,a1和a2是X的实例,Y是类型分配器< U>和b是分配器U的实例.
来自:§17.6.3.5(分配者要求)
a1 == a2 returns true only if storage allocated from each can be deallocated via the other. operator == shall be reflexive,symmetric,and transitive,and shall not exit via an exception. a1 != a2 : same as !(a1 == a2) a == b : same as a == Y::rebind<T>::other(b) a != b : same as !(a == b) X a1(a); Shall not exit via an exception. post: a1 == a X a(b); Shall not exit via an exception. post: Y(a) == b,a == X(b)
所以,我读到的方式,分配者< T>由Allocator U不一定互换.该标准只需要一个== b必须等于Y(a)== b,而不是一个== b必须是真的!
我认为跨类型复制构造函数的要求使得这种混乱.但是,如果我有一个分配器< T>的方式,那么它必须有一个复制构造函数,它使用一个分配器< U>但并不意味着:
Allocator<T> alloc1; Allocator<U> alloc2(alloc1); assert(alloc2 == alloc1);
换句话说,我读这个的方式,上面的断言被允许失败.但我对这里的理解没有信心,因为:
> accepted answer to this question否则说,回答者是一个具有108K声望的人
>复制构造函数要求与标准中的等式要求之间的相互作用有点令人困惑,我可能会误会语言.
那么我在这里是否正确? (顺便说一下,boost::pool_allocator
的实现似乎意味着我是正确的,假设boost开发人员关心标准合规性,因为这个分配器不可互换类型边界.)
解决方法
X a(b)
; Shall not exit via an exception. post:Y(a) == b
,a == X(b)
与你的结论冲突.
using X = Allocator<T>; using Y = Allocator<U>; Y b; X a(b); assert(Y(a) == b); assert(a == X(b)); // therefore assert(a == b);