繁体   English   中英

size_type可以大于std :: size_t吗?

[英]Can a size_type ever be larger than std::size_t?

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

是的,这在某些情况下可能有用。

假设您有一个程序希望访问的存储空间超过虚拟内存容量。 通过创建引用内存映射存储的分配器并在间接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 ,断言是:

p指向的区域中的所有n T对象应在此呼叫之前销毁。

注意区域 ,而不是数组 另一点是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) + n应该与p + n相同。

对于在另一个模型中可表达的模型来说,包含在外部模型中无法表示的对象是完全合法的; 例如,数学逻辑中的非标准模型。

size_t是通过应用sizeof获得的无符号整数的sizeof

sizeof应该返回作为其参数的类型(或表达式类型)的大小。 在数组的情况下,它应该返回整个数组的大小。

这意味着:

  • 不能有任何大于size_t可以表示的结构或联合。

  • 不能有任何大于size_t可以表示的数组。

换句话说,如果某些东西适合你可以访问的最大连续内存块,那么它的大小必须适合size_t(非便携式,但易于直观地理解,这意味着在大多数系统中size_tvoid*一样大) 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_tsize_type吗?

@BenVoight和@ecatmur都建议使用后备存储是文件的用例。 但是,如果后备存储是仅用于内容的文件,并且您在内存中有一些引用该内容的内容(让我们称之为“句柄”),那么您实际上在做一个包含句柄的容器。 句柄将是某个类的实例,它将实际数据存储在文件中,并且只保留在内存中检索该数据所需的任何内容,但这与容器无关:容器将存储句柄,这些句柄位于内存中,我们仍处于“正常”地址空间,因此我的初始响应仍然有效。

然而,还有另一种情况。 你没有分配句柄,你实际上是在文件(或数据库)中存储东西,你的分配器(和相对特征)定义指针,const指针,void指针,const void指针等直接管理该后备存储的类型。 在这种情况下,当然,他们还需要定义size_type (替换size_t )和difference_type (替换ptrdiff_t)来匹配。

size_t已经与最大实现提供的原始整数类型(如果没有,那么没有困难)一样大时,将size_type (和difference_type )定义为大于size_t的直接困难与它们需要是integer types的事实有关。

根据您对标准的解释方式,这可能是不可能的(因为根据标准integer types是标准中定义的类型加上实现提供的extended integer types )或者可能(如果您将其解释为可以提供extended integer type你自己)只要你能编写一个行为与基本类型完全相同的类。 这在过去是不可能的(重载规则确实使原始类型总是与用户定义的类型区分开来),但我不是100%最新的C ++ 11,这可能(或可能不会改变)。

然而,也存在间接困难。 您不仅需要为size_type提供合适的整数类型。 您还需要提供其余的分配器接口。

我一直在考虑它,我看到的一个问题是根据17.6.3.5实现*p 在那个*p语法中, p是由分配器特征键入的pointer 当然,我们可以编写一个类并定义一个operator* (nullary方法版本,执行指针解除引用)。 有人可能认为这可以通过'分页'文件的相对部分轻松完成(如@ecatmur建议的那样)。 但是有一个问题: *p必须是该对象的T& 因此,对象本身必须适合内存,更重要的是,因为您可以执行T &ref = *p并无限期地保留该引用,一旦您在数据中分页,您将永远不会被允许再将其分页。 这意味着有效地可能无法正确实现这样的分配器,除非整个后备存储也可以加载到内存中。

这些是我早期的观察,似乎确实证实了我的第一印象,即真正的答案是否定的:没有实际可行的方法。

然而,正如你所看到的,事情要比直觉似乎更为复杂。 找到一个明确的答案可能需要相当长的时间(我可能会或可能不会继续进一步研究这个话题)。

目前我只想说: 似乎不可能 如果声明不完全基于直觉,则只能接受相反的陈述:发布代码并让人们争论如果你的代码完全符合17.6.3.5以及你的size_type (即使size_t大于size_t也应大于size_t )最大的原始整数类型)可以被认为是整数类型。

是的,不是。

正如@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的回答,因为我认为这是正确的。

从§18.2/ 6开始

类型size_t是一个实现定义的无符号整数类型,它足够大,可以包含任何对象的字节大小。

因此,如果您可以分配一个大小无法用size_t表示的对象,那么它将使实现不符合要求。

要添加到“标准”答案,还要注意stxxl项目,该项目应该能够使用磁盘存储(可能通过扩展,网络存储)处理数TB的数据。 例如,将size_type第731 第742行 )定义为uint64,请参见vector标题

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

不必要。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM