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::pointerX::const_pointerX::void_pointerX::const_void_pointertypes应满足NullablePointer(17.6.3.3)的要求。 这些types的构造函数,比较运算符,复制操作,移动操作或交换操作都不应通过exception退出。 X::pointerX::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_tvoid*并且可以“测量”整个虚拟地址空间)。

编辑:这下一句话可能是错的。 见下文

因此,答案是有可能有一个分配器,分配大小不能由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_tsize_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

typessize_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)。