我对某事感到困惑。假设我有一个任意的C ++分配器 - 比如说:
template<class T>
struct my_allocator
{
template<class Other>
struct rebind { typedef my_allocator<Other> other; };
// [other members here]
};
现在考虑以下代码(请阅读评论):
typedef my_allocator<int> Alloc;
Alloc alloc = get_my_allocator(); // assume this works properly
long *const p = Alloc::rebind<long>::other(alloc).allocate(1, NULL);
// Notice that the rebound allocator for 'long' is now destroyed
// Can a NEW rebound allocator for 'long' deallocate the memory from the old one?
Alloc::rebind<long>::other(alloc).deallocate(p, 1);
// i.e., does the 'int' allocator 'alloc' keep alive the 'long' memory pool too?
在什么时候可以释放后备存储池?
或者,换句话说:哪个分配器共享内存池的所有权?
我一直认为 - 没有太多第二个想法 - 相同值类型的分配器共享其拥有内存池的所有权,但现在它发生在我身上即使他们管理完全不同的类型,他们也可能共享所有反弹分配器背后的内存池的所有权。
反弹类型的分配器必须“保持”彼此的内存池,直到所有被销毁?
如果C ++ 03和C ++ 11的答案不同,请解释它们之间以及它们之间的区别。
答案 0 :(得分:11)
反弹类型的分配器必须“保持”彼此的内存池,直到所有内存池都被销毁?
简短的回答是肯定的,尽管有道理。答案很长......
C ++ 11(和C ++ 14)说[allocator.requirements]从my_allocator<long>
构造的my_allocator<int>
必须能够删除从my_allocator<int>
分配的内存。这在分配器要求表中表示为:
X a(b);
后置条件:
Y(a) == b and a == X(b)
如您所知,operator ==用于表示:两个相等的分配器可以释放彼此分配的指针。此外,b
表格Y
是X
类型的对象,其中Y
和rebind
是my_allocator<int>
相关的分配器,如上所示。
现在,仅凭你的问题a1 == a2
从未实际分配任何东西。然而,同一个表中的另一行继续说出有关分配器的运算符==:
my_allocator<long>
后置条件:
仅当可以释放从每个分配的存储时,才返回true 通过另一个。 operator ==应该是自反的,对称的,和 传递,不得通过例外退出。
(强调是我自己的)
传递意味着如果a1 == a2,a2 == a3,那么暗示a1 == a3。
这个细节指出了你的问题。第一个临时alloc
从alloc
复制,因此等于my_allocator<long>
。
第二个临时alloc
也会从alloc
复制,因此也等于my_allocator<long>
。此外,由于传递属性,两个临时{{1}}也必须彼此相等。
这并不意味着他们都必须共享相同的内存池。但它确实意味着所有这三个分配器必须能够以某种方式释放彼此分配的指针。即你的例子需要工作。
C ++ 03缺乏“传递”要求。话虽这么说,对C ++ 11措辞的“传递”的加入被认为仅仅是C ++ 03意图的“清理”,而不是新的要求。因此,语言律师可以争论C ++ 98/03中是否需要传递,但从实际的角度来看,代码更好地假设它是,因为这是意图。
事实上,C ++ 98/03也包含了这种“黄鼠狼”的措辞(不再是C ++ 11/14):
需要给定分配器类型的所有实例 可互换,总是相互比较。
即。允许C ++ 98/03容器假设所有实例(实际上甚至是反弹实例)总是相等。官方对“有状态”分配器的支持并没有真正开始,直到C ++ 11。