【问题标题】:Does a For loop with Vector iterator copy values, making it inefficient? [duplicate]带有 Vector 迭代器的 For 循环是否会复制值,从而使其效率低下? [复制]
【发布时间】:2021-07-08 00:24:34
【问题描述】:

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

谢谢,

【问题讨论】:

  • 你也可以写for(const MyStruct&amp; oneStruct : myStructList)来确保避免不必要的复制。
  • 我相信从 Clang 10 开始,如果迭代器中存在实际的“隐藏”副本,它现在会发出警告。
  • for (const auto&amp; i : myStructList)。真的没有理由打扰这种类型。

标签: c++ for-loop stdvector


【解决方案1】:

我在 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&lt;&lt; 函数,您可以看到在此之前完成了大复制。

您应该在for 循环中的MyStructoneStruct 之间添加&amp;,以使其成为引用并避免不必要的数据复制。这是a result 的一部分,添加了&amp;

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

现在你可以看到大复制被消除了,指向结构的指针直接用于执行operator&lt;&lt;

【讨论】:

    猜你喜欢
    • 2014-06-11
    • 1970-01-01
    • 1970-01-01
    • 2018-07-05
    • 2015-12-23
    • 2021-10-10
    • 2020-10-10
    • 2012-09-20
    相关资源
    最近更新 更多