size_type可以大于std :: size_t吗?

时间:2012-09-19 16:12:00

标签: c++ stl allocator size-t

std::allocator的标准容器有size_type defined as std::size_t。但是,是否可以使用分配器来分配大小无法用size_t表示的对象?换句话说,size_type是否可以大于size_t

7 个答案:

答案 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::pointerX::const_pointerX::void_pointerX::const_void_pointer类型应满足   NullablePointer的要求(17.6.3.3)。没有构造函数,比较运算符,复制操作,   对这些类型的移动操作或交换操作应通过异常退出。 X::pointerX::const_pointer也应满足随机访问迭代器(24.2)的要求。

此处不要求(&*p) + np + 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_typeline 731line 742)定义为uint64。

这是使用尺寸大于内存所能承受的容器的一个具体示例,或者即使系统的整数也可以处理。

答案 6 :(得分:0)

不一定。

我假设size_type是指大多数STL容器中的typedef?

如果是这样,那么只是因为size_type被添加到所有容器中 只使用size_t意味着STL保留了制作权 size_type他们喜欢的任何类型。 (默认情况下,在所有实现中我都知道 size_type是size_t的typedef。