当前位置: 首页 > 知识库问答 >
问题:

带有向量迭代器的For循环是否会复制值,从而导致效率低下?[副本]

宫高义
2023-03-14

我使用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];
}

谢谢,

共有1个答案

鲜于谦
2023-03-14

我在编译器资源管理器上进行了测试,发现即使使用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;
    }
}

以下是部分结果:

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对应于操作员

您应该添加

test():
        pushq   %r12
        pushq   %rbp
        pushq   %rbx
        subq    $16, %rsp
        movq    myStructList(%rip), %rbp
        movq    myStructList+8(%rip), %r12
        cmpq    %r12, %rbp
        je      .L8
        subq    $-128, %rbp
.L11:
        leaq    -128(%rbp), %rbx
.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
        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

现在您可以看到,消除了大型复制,指向结构的指针直接用于执行操作符

 类似资料:
  • 我有以下python生成器: 而且我想在Java中实现一个迭代器,它的行为有点像以前的生成器。我试图使用两个内部迭代器,但它不起作用。想法?

  • 问题内容: 我想了解更多有关的信息,所以如果我错了,请纠正我。 迭代器是一个对象,该对象具有指向下一个对象的指针,并作为缓冲区或流(即,链表)读取。它们特别有效,因为它们所做的只是通过引用而不是使用索引来告诉您下一步是什么。 但是我仍然不明白为什么会发生以下行为: 经过迭代器()的第一个循环后,就好像它已被消耗并且留空,因此第二个循环()不输出任何内容。 但是,我从未为变量分配新值。 循环幕后到底

  • 迭代器无效是如何处理的,而不是循环? 例如,这段代码不起作用,因为迭代器在插入后无效: 但是,如果我用这个for循环替换while循环,它会正确编译和运行: 为什么for循环有效而while循环无效?

  • 问题内容: (对于那些熟悉JVM编译和优化技巧的人来说是一个问题… :-) 是否有任何一种“ for”和“ foreach”模式明显优于另一种? 考虑以下两个示例: 是快或慢? 假设在这两种情况下,阵列都不需要进行任何健全性检查,是否有明显的获胜者或仍然太接近而无法进行跟注? 编辑:正如在某些答案中指出的,数组的性能应该相同,而“ foreach”模式对于像列表这样的抽象数据类型可能会稍好一些。

  • 当我开始我的代码 我得到无限循环。为什么?

  • 问题内容: 这是我的代码: 增强的循环提供: 虽然此循环语句有效。为什么?代码有什么问题? 问题答案: 在这种情况下,将分配给数组中的每个元素-它 不是 数组的索引。 您想要做的是: 在您的代码中,您试图在迭代对象引用的数组索引处选择整数。换句话说,您的代码等效于: