指针加1遍历数组的元素是否更快?
Is it faster to iterate through the elements of an array with pointers incremented by 1?
这样做会更快吗?
for ( int * pa(arr), * pb(arr+n); pa != pb; ++pa )
{
// do something with *pa
}
比
for ( size_t k = 0; k < n; ++k )
{
// do something with arr[k]
}
? ?
我理解arr[k]
相当于*(arr+k)
,但在第一种方法中,您使用的是递增1的当前指针,而在第二种情况下,您使用的是从arr
递增的连续较大数字的指针。也许硬件有特殊的加1的方法,所以第一种方法更快?或不呢?只是好奇。希望我的问题有意义。
如果编译器足够聪明(大多数编译器都是),那么两个循环的性能应该是相等的。
例如,我用生成程序集编译了gcc 5.1.0中的代码:
int __attribute__ ((noinline)) compute1(int* arr, int n)
{
int sum = 0;
for(int i = 0; i < n; ++i)
{
sum += arr[i];
}
return sum;
}
int __attribute__ ((noinline)) compute2(int* arr, int n)
{
int sum = 0;
for(int * pa(arr), * pb(arr+n); pa != pb; ++pa)
{
sum += *pa;
}
return sum;
}
,结果程序集为:
compute1(int*, int):
testl %esi, %esi
jle .L4
leal -1(%rsi), %eax
leaq 4(%rdi,%rax,4), %rdx
xorl %eax, %eax
.L3:
addl (%rdi), %eax
addq $4, %rdi
cmpq %rdx, %rdi
jne .L3
rep ret
.L4:
xorl %eax, %eax
ret
compute2(int*, int):
movslq %esi, %rsi
xorl %eax, %eax
leaq (%rdi,%rsi,4), %rdx
cmpq %rdx, %rdi
je .L10
.L9:
addl (%rdi), %eax
addq $4, %rdi
cmpq %rdi, %rdx
jne .L9
rep ret
.L10:
rep ret
main:
xorl %eax, %eax
ret
如您所见,两个函数中最重的部分(循环)是相等的:
.L9:
addl (%rdi), %eax
addq $4, %rdi
cmpq %rdi, %rdx
jne .L9
rep ret
但是在更复杂的示例或其他编译器中,结果可能会有所不同。所以你应该测试和测量它,但是大多数编译器生成类似的代码。
完整的代码示例:https://goo.gl/mpqSS0无法回答。这取决于你的编译器和你的机器。
一个非常幼稚的编译器会将代码按原形翻译成机器码。大多数机器确实提供了一个非常快的增量操作。它们通常还为带有偏移量的地址提供相对寻址。这可能比绝对寻址多花几个周期。所以,是的,使用指针的版本可能会更快。但是要考虑到每台机器都是不同的,并且只要程序的可观察行为不改变,编译器就可以进行优化。考虑到这一点,我建议一个合理的编译器将从两个版本创建的代码在性能上没有差异。
任何合理的编译器都会在这两种选择的循环内生成相同的代码-我查看了为迭代std::vector
而生成的代码,使用for循环和迭代器的整数或使用for( auto i: vec)
类型构造[std::vector
内部有两个指针用于存储值的begin
和end
,所以像您的pa
和pb
]。gcc和clang都在循环本身内生成相同的代码[在不同的编译器之间,循环的确切细节略有不同,但除此之外,没有区别]。循环的设置略有不同,但除非你经常做少于5个项目的循环,否则你为什么要担心呢?]时,重要的是循环的实际内容,而不是实际循环前的位。
对于所有性能很重要的代码,确切的代码,编译器和版本,编译器选项,处理器和模型,将对代码的执行产生影响。但是对于绝大多数的处理器和编译器,我不希望有明显的区别。如果代码真的很关键,衡量不同的替代方案,看看哪种方法最适合您的情况。
- 是否可以在c++中处理字符串流中的各个元素
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 检查 2D 网格的某个元素是否与另一个元素共享对角线、水平线或垂直线
- 是否可以使用 new 指定具有宏常量的动态分配数组的元素?
- C++:带有大括号初始化列表的函数调用表达式 - 标准是否规定在单个元素列表的微不足道的情况下忽略大括号?
- 如何知道地图中的最后一个元素是否被删除?
- 检查 TinyXML 中的元素是否存在
- 经过最后一个数组元素末尾的指针是否应该等于超过整个数组末尾的指针?
- 是否需要 mutex() 来安全地同时访问具有 2 个线程的数组的不同元素?
- 是否有用于元素部分移位的 simd 指令/内在/内置指令?
- 是否有具有外部元素分配的序列容器(在 STL 中)?
- C++:是否可以编写一个函数,将不同类型的元素附加到变体数组中?
- 数组对象的生存期是否在重用其元素存储时结束?
- 擦除是否删除 stl 无序列图元素使用的堆内存
- 调用 erase() 函数是否也会在擦除元素之前更改迭代器值?
- 是否有一个 std::set 函数来确定不超过数字 x 的最大元素?
- 除了 std::vector 之外,是否有一个 std 容器不会复制和销毁作为类的元素?
- 是否可以使用宏来访问动态数组或向量中的元素或为其赋值
- 如果我在相应 char 数组的声明中为其提供额外的元素,是否会自动设置 NULL?
- 使用 at() 访问 std::map 元素是否比运算符 [] 慢?