Fre*_*Foo 36 c++ stl size-t allocator
标准容器,std::allocator其size_type定义为std::size_t.但是,是否可以使用分配器来分配大小无法用size_t?表示的对象?换句话说,可以size_type永远大于size_t?
eca*_*mur 25
是的,这在某些情况下可能有用.
假设您有一个程序希望访问的存储空间超过虚拟内存容量.通过创建引用内存映射存储的分配器并在间接pointer对象时根据需要进行映射,可以访问任意大量的内存.
这仍然符合18.2:6,因为它size_t被定义为足以包含任何对象的大小,但是17.6.3.5:2表28定义size_type为包含分配模型中最大对象的大小,它不必是实际对象在C++内存模型中.
注意,表18中的17.6.3.5:2中的要求并不构成多个对象的分配应该产生数组的要求; 对于allocate(n)要求是:
内存分配给
n类型的对象T
并且deallocate断言是:
nT指定区域内的所有物体p应在此呼叫之前销毁.
注意区域,而不是数组.另一点是17.6.3.5:4:
的
X::pointer,X::const_pointer,X::void_pointer,和X::const_void_pointer类型应满足NullablePointer(17.6.3.3)的要求.对这些类型的构造函数,比较运算符,复制操作,移动操作或交换操作不应通过异常退出.X::pointer并且X::const_pointer还应满足随机访问迭代器的要求(24.2).
这里没有要求(&*p) + n应该是相同的p + n.
对于在另一个模型中可表达的模型来说,包含在外部模型中无法表示的对象是完全合法的; 例如,数学逻辑中的非标准模型.
Ana*_*ile 19
size_t是通过应用获得的无符号整数的类型sizeof.
sizeof应该返回作为其参数的类型(或表达式类型)的大小.在数组的情况下,它应该返回整个数组的大小.
这意味着:
不能有任何比size_t可以代表的更大的结构或联合.
不能有任何大于size_t可以表示的数组.
换句话说,如果某些东西适合你可以访问的最大连续内存块,那么它的大小必须适合size_t(在非便携式中,但是直观易于理解,这意味着在大多数系统上size_t都是如此大void*而且可以'测量'整个虚拟地址空间).
编辑:下一句可能是错的.见下文
因此,答案是否有可能有一个分配器分配大小不能用size_t?表示的对象?没有.
编辑(附录):
我一直在想它,而上面我实际上是错的.我检查了标准,似乎可以设计一个完全自定义指针类型的完全自定义分配器,包括使用不同类型的指针,const指针,void指针和const void指针.因此,分配器实际上可以具有大于size_t的size_type.
但要这样做,您需要实际定义完全自定义指针类型以及相应的allocator和allocator traits实例.
我说的原因可能是我仍然有点不清楚是否size_type需要跨越单个对象的大小或者分配器模型中的多个对象(即数组)的大小.我需要调查这个细节(但现在不是,这是晚餐时间:))
Edit2(新附录):
@larsmans我想你可能想要决定接受什么.问题似乎比人们直观地意识到的要复杂得多.我正在编辑答案,因为我的想法绝对不仅仅是评论(内容和大小).
ReEdit(正如评论中指出的那样,下两段不正确):
首先size_type只是一个名字.你当然可以定义一个容器,并size_type用你想要的任何含义添加一个容器.你size_type可以是一个浮子,一个字符串.
也就是说,在容器size_type中定义标准库容器只是为了便于访问.事实上,它应该与size_type该容器的分配器相同(并且size_type分配器的分配器应该是该分配器size_type的allotator_traits).
因此,我们今后将假设size_type容器(即使是您定义的容器)遵循"按惯例"的相同逻辑.@BenVoight开始回答"正如@AnalogFile解释的那样,没有分配的内存可以大于size_t.所以从分配器继承其size_type的容器不能使size_type大于size_t.".事实上,我们现在规定如果一个容器有size_type来自分配器的那个(他说继承,但那当然不是类继承的常识).
然而,他可能或可能不是100%正确的size_type(即使它来自分配器)必然受到限制size_t.问题实际上是:分配器(以及相应的特征)能否定义size_type大于size_t?的分配器?
@BenVoight和@ecatmur都建议使用后备存储是文件的用例.但是,如果后备存储是仅用于内容的文件,并且您在内存中有一些引用该内容的内容(让我们称之为"句柄"),那么您实际上在做一个包含句柄的容器.句柄将是某个类的实例,它将实际数据存储在文件中,并且只保留在内存中检索该数据所需的任何内容,但这与容器无关:容器将存储句柄,这些句柄位于内存中,我们仍处于"正常"地址空间,因此我的初始响应仍然有效.
然而,还有另一种情况.你没有分配句柄,你实际上是在文件(或数据库)中存储东西,你的分配器(和相对特征)定义指针,const指针,void指针,const void指针等直接管理该后备存储的类型.在这种情况下,当然,他们还需要定义size_type(替换size_t)和difference_type(替换ptrdiff_t)来匹配.
定义size_type(和difference_type)大于size_t何时的直接困难size_t已经与最大实现一样大,提供了原始整数类型(如果没有,那么没有困难)与它们需要的事实有关integer types.
根据您对标准的解释方式,这可能是不可能的(因为根据标准integer types是标准中定义的类型加上实施extended integer types提供的类型)或可能(如果您将其解释为可以extended integer type自己提供),只要您可以编写一个行为与原始类型完全相同的类.这在过去是不可能的(重载规则确实使原始类型总是与用户定义的类型区分开来),但我不是100%最新的C++ 11,这可能(或可能不会改变).
然而,也存在间接困难.您不仅需要提供合适的整数类型size_type.您还需要提供其余的分配器接口.
我一直在考虑它,我看到的一个问题是*p根据17.6.3.5 实现.在该*p语法中,p是pointer由分配器特征键入的语法.当然我们可以编写一个类并定义一个operator*(nullary方法版本,做指针解除引用).人们可能会认为这可以通过"分页"文件的相对部分轻松完成(如@ecatmur建议的那样).但是有一个问题:*p必须是T&对象.因此,对象本身必须适合内存,更重要的是,因为您可以T &ref = *p无限期地执行并保持该引用,一旦您在数据中分页,您将永远不会被允许再将其分页.这意味着有效地可能无法正确实现这样的分配器,除非整个后备存储也可以加载到内存中.
这些是我早期的观察,似乎确实证实了我的第一印象,即真正的答案是否定的:没有实际可行的方法.
然而,正如你所看到的,事情要比直觉似乎更为复杂.找到一个明确的答案可能需要相当长的时间(我可能会或可能不会继续进一步研究该主题).
目前我只想说:似乎不可能.声明相反,只应如果他们不完全基于直觉是可以接受的:邮编,让人们争论,如果你的代码完全符合17.6.3.5,如果你size_type(须大于size_t即使size_t是作为世界上最大的原始大整数类型)可以被认为是整数类型.
Ben*_*igt 15
是的,不是.
正如@AnalogFile所解释的那样,没有分配的内存可以大于size_t.所以size_type从分配器继承它的容器不能size_type大于size_t.
但是,您可以设计一个容器类型,表示不完全存储在可寻址内存中的集合.例如,成员可以位于磁盘上或数据库中.它们甚至可以动态计算,例如Fibonacci序列,并且从不存储在任何地方.在这种情况下,size_type可能很容易大于size_t.
我确定它被埋在标准的某个地方,但我见过的最好的size_type描述来自SGI-STL文档.正如我所说的那样,我确信它符合标准,如果有人能够指出它,那么一定要做到.
根据SGI,容器的size_type是:
无符号整数类型,可表示容器距离类型的任何非负值
除此之外,它没有任何声明.理论上,您可以定义一个使用uint64_t,unsigned char以及其他任何内容的容器.它引用容器的distance_type是我觉得有趣的部分,因为......
distance_type:一个带符号的整数类型,用于表示两个容器迭代器之间的距离.此类型必须与迭代器的距离类型相同.
但是,这并没有真正回答这个问题,但是看看size_type和size_t的不同(或者可以)有趣.关于你的问题,请参阅(和投票)@AnalogFile的回答,因为我认为这是正确的.
| 归档时间: |
|
| 查看次数: |
2341 次 |
| 最近记录: |