size_type是否可以大于std :: size_t?
具有std::allocator
标准容器的size_type
定义为std::size_t
。 然而,是否有可能有一个分配器的大小不能用size_t
表示的对象? 换句话说, size_type
是否可以比size_t
?
是的,这在某些情况下可能有用。
假设你有一个程序希望访问比适合虚拟内存更多的存储空间。 通过创build引用内存映射存储的分配器,并在间接pointer
对象时根据需要映射它,可以访问任意大量的内存。
这与18.2:6保持一致,因为size_t
被定义为足够大以包含任何对象的大小,但是17.6.3.5:2表28将size_type
定义为包含分配模型中的最大对象的大小,其不一定是C ++内存模型中的实际对象。
请注意,表17.6.3.5:2中的要求并不构成多个对象的分配应导致数组的要求; 对于allocate(n)
的要求是:
内存分配给types为
T
n
对象
并且deallocate
这个断言是:
在
p
指向的区域内的所有n
T
物体都应该在这个调用之前销毁。
注意区域 ,而不是数组 。 还有一点是17.6.3.5:4:
X::pointer
,X::const_pointer
,X::void_pointer
和X::const_void_pointer
types应满足NullablePointer(17.6.3.3)的要求。 这些types的构造函数,比较运算符,复制操作,移动操作或交换操作都不应通过exception退出。X::pointer
和X::const_pointer
也应满足随机访问迭代器(24.2)的要求。
这里没有要求(&*p) + n
应该和p + n
相同。
对另一个模型中可expression的模型来说,包含在外部模型中不可表示的对象是完全合理的; 例如math逻辑中的非标准模型。
size_t
是通过应用sizeof
得到的无符号整数的sizeof
。
sizeof
应返回作为参数的types(或expression式types)的大小。 在数组的情况下,它应该返回整个数组的大小。
这意味着:
-
不能有任何大于
size_t
可以表示的结构或联合。 -
不能有任何大于
size_t
可以表示的数组。
换句话说,如果某个东西适合你可以访问的连续内存的最大块,那么它的大小必须适合size_t(非便携式,但是直观地理解,这意味着在大多数系统中size_t
与void*
并且可以“测量”整个虚拟地址空间)。
编辑:这下一句话可能是错的。 见下文
因此,答案是有可能有一个分配器,分配大小不能由size_t
代表的对象? 没有。
编辑(附录):
我一直在想这个,上面的我其实是错的。 我检查了标准,似乎有可能devise一个完全自定义的指针types的定制分配器,包括使用不同types的指针,常量指针,空指针和常量空指针。 因此,分配器实际上可以具有比size_t大的size_type。
但要做到这一点,你需要实际定义完全自定义的指针types和相应的分配器和分配器特征实例。
我说的原因可能是我还有点不清楚,如果size_type
需要跨越单个对象的大小,或者也是分配器模型中的多个对象(这是一个数组)的大小。 我将需要调查这些细节(但不是现在,这是在这里的晚餐时间:))
编辑2(新增编):
@larsmans我想你可能想决定接受什么。 这个问题似乎比人们可以直观地认识到的复杂一点。 我正在编辑答案,因为我的想法绝不仅仅是评论(内容和大小)。
重新编辑(正如在评论中指出的,接下来的两段是不正确的):
首先size_type
只是一个名字。 你当然可以定义一个容器,并为其添加一个size_type
,以任何你想要的意义。 你的size_type
可以是一个浮点数,一个string。
也就是说在标准库容器中,容器中定义的size_type
只是为了方便访问。 它实际上应该与该容器的分配器的size_type
相同(并且分配器的size_type
应该是该分配器的allotator_traits的size_type
)。
因此,我们今后应该假定容器的size_type
,即使是你定义的,也遵循相同的逻辑“按照惯例”。 @BenVoight以“@AnalogFile解释说,没有分配的内存可以比size_t大,所以从分配器inheritancesize_type的容器的size_type不能大于size_t”。 实际上,我们现在正在规定,如果一个容器有一个size_type
那么来自allocator(他说inheritance,但这当然不是类inheritance的常识)。
然而,他可能会也可能不会100%正确, size_type
(即使它来自分配器)必然受限于size_t
。 问题的确是:分配器(和相应的特性)是否可以定义大于size_t
的size_type
?
@BenVoight和@ecatmur都提供了一个用例,其中后备存储是一个文件。 但是,如果后备存储只是一个文件的内容,并且你在内存中引用了这个内容(我们称之为“句柄”),那么你实际上在做一个包含句柄的容器。 一个句柄将是某个类的一个实例,它将实际的数据存储在一个文件中,并且只保存在内存中,而不pipe它是否需要检索这些数据,但是这与容器无关:容器将把句柄存储起来,我们仍然处于“正常”地址空间,所以我的初始响应仍然有效。
还有另一种情况。 你没有分配句柄,你实际上是在文件(或数据库)中存储东西,而你的分配器(和相对特征)定义了直接pipe理该后备存储的指针,常量指针,空指针,常量空指针等types。 在这种情况下,他们当然也需要定义size_type
(replacesize_t
)和difference_type
(replaceptrdiff_t)来匹配。
size_type
(和difference_type
)定义为size_t
大于size_t
的直接困难已经和提供原始整数types的最大实现一样大(如果不是,那么没有困难)与它们需要是integer types
。
根据你如何解释标准,这可能是不可能的(因为根据标准的integer types
是在标准中定义的types加上实现提供的extended integer types
)或者可能的(如果你解释它可以提供一个extended integer type
你自己),只要你可以写一个行为完全像一个基本types的类。 这在旧时代是不可能的(重载规则确实使原始types总是与用户定义的types区分开来),但是我并不是100%最新的C ++ 11,这可能(或者可能不会改变)。
但也有间接的困难。 您不仅需要为size_type
提供合适的整数types。 您还需要提供分配器接口的其余部分。
我一直在想这个问题,我看到的一个问题是根据17.6.3.5实现*p
。 在*p
语法中, p
是一个由分配器特征键入的pointer
。 当然我们可以编写一个类并定义一个operator*
(空方法的版本,做指针的dereferece)。 有人可能会认为这可以通过“分页”文件的相关部分来完成(就像@ecatmur所build议的那样)。 但是有一个问题: *p
必须是一个T&
的对象。 因此,对象本身必须适应内存,更重要的是,因为你可以做T &ref = *p
并且无限期地持有这个引用,所以一旦你在数据中进行了分页,你就不会再被分页了。 这意味着实际上可能没有办法正确地实现这样的分配器,除非整个后备存储器也可以被加载到存储器中。
这些是我早期的观察,似乎确实证实了我的第一印象,即真正的答案是否定的:没有切实可行的办法。
然而,正如你所看到的,事情比纯粹的直觉似乎暗示要复杂得多。 find一个明确的答案可能需要相当长的时间(我可能会或可能不会继续研究这个话题)。
目前我只会说: 似乎不可能 。 相反的语句只有在不直接基于直觉的情况下才能被接受:邮政编码和让人们辩论,如果你的代码完全符合17.6.3.5,并且你的size_type
(即使size_t
一样大,最大的原始整数types)可以被认为是整数types。
是和不是。
正如@AnalogFile所解释的,没有分配的内存可以比size_t
。 所以一个从分配器inheritancesize_type
的容器的size_type
不能大于size_t
。
但是,您可以devise一个代表未被存储在可寻址内存中的集合的容器types。 例如,成员可以在磁盘上或数据库中。 它们甚至可以dynamic计算,例如Fibonacci序列,并且永远不会存储在任何地方。 在这种情况下, size_type
可能会比size_t
更大。
我确定它被埋在标准的某个地方,但是我所见过的size_type的最好的描述来自SGI-STL文档。 正如我所说,我确定它是在标准的,如果有人能指出,通过一切手段。
根据SGI的说法,一个容器的size_type是:
一个无符号的整型,可以表示容器距离types的非负值
除此之外,没有任何声明是必须的。 理论上你可以定义一个使用uint64_t,unsigned char和其他任何东西的容器。 它是引用容器的distance_type是我觉得有趣的部分,因为…
distance_type:用于表示两个容器迭代器之间距离的有符号整型。 这个types必须和迭代器的距离types一样。
但是,这并没有真正回答这个问题,但是看看size_type和size_t是如何不同的(或者可以)是很有趣的。 关于你的问题,看到(和投票)@AnalogFile的答案,因为我相信它是正确的。
从§18.2/ 6
types
size_t
是一个实现定义的无符号整数types,其大小足以包含任何对象的字节大小。
所以,如果你可以分配一个大小不能用size_t
表示的对象,那么它会使实现不合格。
要增加“标准”答案,还要注意stxxl项目,该项目应该能够使用磁盘存储(也许通过扩展,networking存储)处理数TB的数据。 例如,查看vector的标题,将size_type
( 第731 行和第742行 )定义为uint64。
这是使用大于内存大小的容器的一个具体例子,或者甚至系统的整数都可以处理。
不必要。
我认为size_type是指大多数STL容器中的typedef?
如果是这样,那么只是因为size_type被添加到所有的容器,而不是仅仅使用size_t,这意味着STL保留使size_type成为他们喜欢的任何types的权利。 (默认情况下,我知道size_type是size_t的typedef)。