std::allocator
的标准容器有size_type
defined as std::size_t
。但是,是否可以使用分配器来分配大小无法用size_t
表示的对象?换句话说,size_type
是否可以大于size_t
?
答案 0 :(得分:25)
是的,在某些情况下这可能很有用。
假设您有一个程序希望访问的存储空间超过虚拟内存容量。通过创建引用内存映射存储的分配器并在间接pointer
对象时根据需要进行映射,可以访问任意大量的内存。
这仍然符合18.2:6,因为size_t
被定义为足以包含任何对象的大小,但是17.6.3.5:2表28将size_type
定义为包含分配模型中最大的对象,它不必是C ++内存模型中的实际对象。
请注意,17.6.3.5:2表28中的要求并不构成要求多个对象的分配应该产生数组;对于allocate(n)
,要求是:
为
类型的n
T
个对象分配内存
和deallocate
断言是:
该区域中的所有
n
T
个对象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
相同。
对于在另一个模型中可表达的模型来说,包含在外部模型中无法表示的对象是完全合法的;例如,数学逻辑中的非标准模型。
答案 1 :(得分:19)
size_t
是您通过应用sizeof
获得的无符号整数的类型。
sizeof
应返回作为其参数的类型(或表达式类型)的大小。在数组的情况下,它应该返回整个数组的大小。
这意味着:
不能有任何大于size_t
可以代表的结构或联合。
不能有任何大于size_t
可以代表的数组。
换句话说,如果某些东西适合你可以访问的最大连续内存块,那么它的大小必须符合size_t(非便携式,但易于直观地理解,这意味着在大多数系统{{1和} size_t
一样大,可以衡量整个虚拟地址空间。
编辑:下一句话可能是错的。见下文
因此的答案是否可以让分配器分配大小无法用void*
表示的对象?是否定的。
编辑(附录):
我一直在考虑它而且上面我实际上是错的。我已经检查了标准,似乎可以设计一个完全自定义指针类型的完全自定义分配器,包括使用不同类型的指针,const指针,void指针和const void指针。因此,分配器实际上可以具有大于size_t的size_type。
但要这样做,您需要实际定义完全自定义指针类型以及相应的allocator和allocator traits实例。
我说可能的原因是我仍然有点不清楚size_t
是否需要跨越单个对象的大小或多个对象的大小(这是分配器模型中的一个数组。我需要调查这个细节(但不是现在,它在这里的晚餐时间:))
Edit2(新附录):
@larsmans我想你可能想要决定接受什么。问题似乎比人们直观地意识到的要复杂得多。我再次编辑答案,因为我的想法绝对不仅仅是评论(无论是内容还是大小)。
ReEdit(正如评论中指出的那样,下两段不正确):
首先,size_type
只是一个名字。您当然可以定义一个容器,并使用您希望的任何含义为其添加size_type
。你的size_type
可以是浮点数,也可以是字符串。
在标准库中说容器size_type
在容器中定义,只是为了便于访问。事实上,它应该与该容器的分配器的size_type
相同(并且分配器的size_type
应该是该分配器的allotator_traits的size_type
)
因此,我们今后将假设容器的size_type
,即使是您定义的容器,遵循相同的逻辑'按惯例'。 @BenVoight用&#34开始他的回答;正如@AnalogFile解释的那样,没有分配的内存可以大于size_t。因此,从分配器继承其size_type的容器的size_type不能大于size_t。"。事实上,我们现在规定如果一个容器有一个size_type
,那么它来自分配器(他说继承,但那当然不是类继承的常识)。
然而,size_type
(即使它来自分配者)必然会被约束为size_type
,这可能是也可能不是100%正确。问题实际上是:分配器(和相应的特征)可以定义大于size_t
的{{1}}吗?
@BenVoight和@ecatmur都建议使用后备存储为文件的用例。但是,如果后备存储是仅用于内容的文件,并且您在内存中有一些引用该内容的内容(让我们称之为'句柄'),那么您实际上是在做一个容器包含句柄。句柄将是某个类的实例,它将实际数据存储在文件中,并且只保留在内存中检索该数据所需的任何内容,但这与容器无关:容器将存储句柄,这些句柄位于内存中,我们仍处于正常状态。地址空间,所以我的初始响应仍然有效。
然而,还有另一种情况。你没有分配句柄,你实际上是在文件(或数据库)中存储东西,你的分配器(和相对特征)定义指针,const指针,void指针,const void指针等直接管理该后备存储的类型。在这种情况下,当然,他们还需要定义size_type
(替换size_t
)和size_type
(替换ptrdiff_t)以匹配。
当size_t
已经与最大的实现一样大时,将difference_type
(和size_type
)定义为大于difference_type
的直接困难提供了原始整数类型(如果不是,那就没有困难)与他们需要size_t
这一事实有关。
根据您对标准的解释方式,这可能是不可能的(因为根据标准size_t
是标准中定义的类型加上实施提供的integer types
)或可能(如果您解释只要你能编写一个像基本类型一样行为完全的类,你就可以自己提供integer types
。这在以前是不可能的(重载规则确实使原始类型总是与用户定义的类型区分开来),但我不是100%与C ++ 11最新,这可能(或可能不会改变) )。
然而,也存在间接困难。您不仅需要为extended integer types
提供合适的整数类型。您还需要提供分配器接口的其余部分。
根据17.6.3.5,我一直在考虑它,我看到的一个问题是实施extended integer type
。在size_type
语法中,*p
是由分配器特征键入的*p
。当然,我们可以编写一个类并定义一个p
(nullary方法版本,执行指针解除引用)。人们可能会认为这可以通过“分页”轻松完成。文件的相对部分(如@ecatmur建议的那样)。但是有一个问题:pointer
必须是该对象的operator*
。因此,对象本身必须适合内存,更重要的是,因为您可以*p
无限期地保留该引用,一旦您在数据中分页,您将永远不会被允许再将其分页。这意味着有效地可能无法正确实现这样的分配器,除非整个后备存储也可以加载到内存中。
这些是我早期的观察,似乎确实证实了我的第一印象,即真实答案是否定的:没有实际可行的方法。
然而,正如你所看到的,事情比单纯的直觉似乎要复杂得多。可能需要相当长的时间才能找到明确的答案(我可能会或可能不会继续进一步研究该主题)。
目前我只是说:似乎不可能。如果声明不完全基于直觉,则只能接受相反的陈述:邮政编码并让人们辩论,如果你的代码完全符合17.6.3.5以及你的T&
(应大于T &ref = *p
即使size_type
与最大的原始整数类型一样大,也可以认为是整数类型。
答案 2 :(得分:15)
是和否。
正如@AnalogFile所解释的,没有分配的内存可以大于size_t
。因此,从分配器继承其size_type
的容器不能size_type
大于size_t
。
但是,您可以设计一个容器类型,表示不完全存储在可寻址内存中的集合。例如,成员可以位于磁盘上或数据库中。它们甚至可以动态计算,例如斐波那契序列,从不存储在任何地方。在这种情况下,size_type
可能很容易大于size_t
。
答案 3 :(得分:5)
我确定它隐藏在标准的某个地方,但我见过size_type的最佳描述来自SGI-STL文档。正如我所说的,我确信它符合标准,如果有人可以指出,那么一定要做。
根据SGI,容器的size_type是:
无符号整数类型,可表示任何非负值 容器的距离类型
除此之外,它没有任何声明。理论上,您可以定义一个使用uint64_t,unsigned char以及其他任何内容的容器。它引用容器的distance_type是我觉得有趣的部分,因为......
distance_type:用于表示距离的有符号整数类型 两个容器的迭代器之间。这种类型必须相同 作为迭代器的距离类型。
但这并没有真正回答这个问题,但看看size_type和size_t如何不同(或可以)是很有趣的。关于你的问题,请参阅(和投票)@AnalogFile的答案,因为我认为这是正确的。
答案 4 :(得分:3)
来自§18.2/ 6
类型
size_t
是一个实现定义的无符号整数类型,其大小足以包含任何对象的字节大小。
因此,如果您可以分配一个大小无法用size_t
表示的对象,那么它将使实现不符合。
答案 5 :(得分:1)
要添加到“标准”答案,还要注意stxxl项目,该项目应该能够使用磁盘存储(可能通过扩展,网络存储)处理数TB的数据。例如,请参阅header of vector,将size_type
(line 731和line 742)定义为uint64。
这是使用尺寸大于内存所能承受的容器的一个具体示例,或者即使系统的整数也可以处理。
答案 6 :(得分:0)
不一定。
我假设size_type是指大多数STL容器中的typedef?
如果是这样,那么只是因为size_type被添加到所有容器中 只使用size_t意味着STL保留了制作权 size_type他们喜欢的任何类型。 (默认情况下,在所有实现中我都知道 size_type是size_t的typedef。