使用int而不是size_t索引访问向量元素是否会降低性能?

3

如果我使用int索引来访问向量元素,它会将整数转换为size_t,然后调用operator[](size_t)函数吗?这样做是否会降低性能?


3
个人资料,自己看就好啦 :) - Borgleader
1
你可以进行测量并找出答案。 - NathanOliver
1
你可以自己比较一下生成的代码。当然它会转换,v[0]使用了一个int,显然这是有效的。 - Jonathan Wakely
在编译器允许int为负数的情况下,在x86_64架构中选择intsize_t会有显著的本地性能成本差异(因为符号扩展相对较昂贵)。显著的本地性能差异可能或可能不会导致可检测的全局性能差异。编译器何时检测特定的int不能为负数?根据我的经验(查看生成的代码),有时候会检测,但比人类明显地少。 - JSF
如果编译器决定进行零扩展而不是符号扩展,那么int可能比size_t。在x86_64中,将32位值复制或计算到64位寄存器中并进行零扩展,始终至少与从64位值复制或计算的相应操作一样快。在某些指令对齐和/或可能出现L1缓存未命中的情况下,使用零扩展的32位复制或计算比从64位值开始要快得多。 - JSF
显示剩余4条评论
2个回答

5
intsize_t之间的主要区别是int是有符号的,而size_t是无符号的。此外,这两种类型的大小可能不同,因为它们都是特定于平台的并且彼此独立的。

当这两个大小相同时,从int转换为size_t是无操作的,因此没有性能影响。

当大小不同时,编译器足够聪明,可以将int索引的部分或扩展值传递到以size_t为参数的operator []中,几乎没有开销,因为缩小大小需要进行部分加载,而扩大大小则需要为上部分加载零。请注意,写入扩展值的上部分的零并不是额外的操作,因为它会替换size_t类型的索引复制上部分。

因此,答案是否定的,您不会看到任何性能差异。


2
我的分析结果与你的分析相矛盾。这可能是因为最新的编译器对未定义行为的优化有所改进,从而修复了这种效果。如果没有这样的改进,编译器在许多情况下允许负的 int,因此它进行符号扩展而不是零扩展,在 x86_64 中,符号扩展可能比零扩展效率低得多。 - JSF
@JSF 请分享您的基准测试结果。由于这种微小差异很难进行基准测试,因为时间主要取决于对向量的实际访问,这取决于硬件缓存的性能。 - Sergey Kalinichenko
抱歉,所有的代码分析都属于我的雇主。我无法分享任何源代码,因此基准测试结果是毫无意义的。几乎所有我的基准测试结果都像您预期的那样被目标数据的缓存未命中所主导,因此在生成的代码中存在广泛的asm代码差异都没有任何影响。只有通过将所有这些设置置于一边,并仅查看生成的代码真正重要的情况下,我才发现符号扩展操作是有意义的。 - JSF
根据分析结果,我们使用unsigned作为索引的数据类型,而不是intsize_t。与典型代码相比,我们的代码有更少的情况,编译器可以安全地决定将int零扩展。我们的代码没有任何包含超过2 ** 31个元素的容器。 (超过2 ** 32字节很常见,但超过2 ** 31个元素还需要几年时间才可能出现)。有些晦涩的情况下,使用unsigned作为索引需要进行微调,以避免比size_t慢。但是,有更多的情况下,unsigned会更快一些,这些情况会累加。 - JSF

0

1
@erip,你在问什么? - Jonathan Wakely
int类型的大小也取决于平台。这个答案是误导性的。 - mabraham
@mabraham - 什么方面误导了? - Leonardo Herrera
@LeonardoHerrera 这个问题涉及到 int 和 size_t。标准允许它们的大小由实现确定,因此使用其中任何一个来索引向量的决定的后果取决于实现。答案只承认 size_t 取决于平台。 - mabraham
我不知道为什么今天阅读中出现了这个问题,但它让我陷入了一个兔子洞。我仍然认为这个答案没有误导性,并回答了“使用'int'访问向量元素是否会有性能惩罚”的问题。答案仍然是“取决于”,因为'size_t'是平台相关的,保证是无符号整数! - Leonardo Herrera

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接