问题描述
我正在使用 for 循环遍历向量中的所有元素,并且我已经看到了漂亮的代码:
std::vector<int> vi;
// ... assume the vector gets populated
for(int i : vi)
{
// do stuff with i
}
但是,从快速测试来看,它似乎每次都将向量中的值复制到 i 中(我尝试在 for 循环中修改 i 并且向量保持不变)。
我问的原因是我实际上是用一个大结构的向量来做这个的。
std::vector<MyStruct> myStructList;
for(MyStruct onestruct : myStructList)
{
cout << onestruct;
}
那么......考虑到内存复制量,这是一种糟糕的做事方式吗?使用传统索引是否更有效?
for(int i=0; i<myStructList.size(); i++)
{
cout << myStructList[i];
}
谢谢,
解决方法
我在 Compiler Explorer 上对此进行了测试,发现即使使用 gcc 10.3 进行 -O3
优化,实际上也可以完成复制。
这是我的测试代码:
#include <iostream>
#include <vector>
using std::cout;
struct MyStruct {
int a[32];
};
std::ostream& operator<<(std::ostream& s,const MyStruct& m) {
for (int i = 0; i < 32; i++) s << m.a[i] << ' ';
return s;
}
std::vector<MyStruct> myStructList;
void test(void) {
for(MyStruct oneStruct : myStructList)
{
cout << oneStruct;
}
}
这是the result的一部分:
test():
pushq %r13
pushq %r12
pushq %rbp
pushq %rbx
subq $152,%rsp
movq myStructList(%rip),%r12
movq myStructList+8(%rip),%r13
cmpq %r13,%r12
je .L8
leaq 144(%rsp),%rbp
.L11:
movdqu (%r12),%xmm0
movdqu 16(%r12),%xmm1
leaq 16(%rsp),%rbx
movdqu 32(%r12),%xmm2
movdqu 48(%r12),%xmm3
movdqu 64(%r12),%xmm4
movdqu 80(%r12),%xmm5
movups %xmm0,16(%rsp)
movdqu 96(%r12),%xmm6
movdqu 112(%r12),%xmm7
movups %xmm1,32(%rsp)
movups %xmm2,48(%rsp)
movups %xmm3,64(%rsp)
movups %xmm4,80(%rsp)
movups %xmm5,96(%rsp)
movups %xmm6,112(%rsp)
movups %xmm7,128(%rsp)
.L10:
movl (%rbx),%esi
movl $_ZSt4cout,%edi
addq $4,%rbx
call std::basic_ostream<char,std::char_traits<char> >::operator<<(int)
movl $1,%edx
leaq 15(%rsp),%rsi
movb $32,15(%rsp)
movq %rax,%rdi
call std::basic_ostream<char,std::char_traits<char> >& std::__ostream_insert<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&,char const*,long)
cmpq %rbp,%rbx
jne .L10
subq $-128,%r12
cmpq %r12,%r13
jne .L11
.L8:
addq $152,%rsp
popq %rbx
popq %rbp
popq %r12
popq %r13
ret
.L10:
和 jne .L11
之间的线对应于 operator<<
函数,可以看到在此之前进行了大复制。
您应该在 &
循环中的 MyStruct
和 oneStruct
之间添加 for
以使其成为参考并避免不需要的数据副本。以下是添加了 &
的 a result 的一部分:
test():
pushq %r12
pushq %rbp
pushq %rbx
subq $16,%rbp
movq myStructList+8(%rip),%rbp
je .L8
subq $-128,%rbp
.L11:
leaq -128(%rbp),%rbx
.L10:
movl (%rbx),%rbx
jne .L10
leaq 128(%rbp),%rax
cmpq %rbp,%r12
je .L8
movq %rax,%rbp
jmp .L11
.L8:
addq $16,%rsp
popq %rbx
popq %rbp
popq %r12
ret
现在你可以看到大复制被消除了,指向结构的指针直接用于operator<<
的执行。