Avoiding if statement inside a for loop?

后端 未结 4 2017
南旧
南旧 2020-12-04 06:54

I have a class called Writer that has a function writeVector like so:

void Drawer::writeVector(vector vec, bool index=true         


        
4条回答
  •  余生分开走
    2020-12-04 07:23

    In most of cases, your code is already good for performance and readability. A good compiler is capable to detect loop invariants and do appropriate optimizations. Consider the following example which is very close to your code:

    #include 
    #include 
    
    void write_vector(int* begin, int* end, bool print_index = false) {
        unsigned index = 0;
        for(int* it = begin; it != end; ++it) {
            if (print_index) {
                std::printf("%d: %d\n", index, *it);
            } else {
                std::printf("%d\n", *it);
            }
            ++index;
        }
    }
    
    int my_vector[] = {
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
    };
    
    
    int main(int argc, char** argv) {
        write_vector(std::begin(my_vector), std::end(my_vector));
    }
    

    I am using the following command line to compile it:

    g++ --version
    g++ (GCC) 4.9.1
    Copyright (C) 2014 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    g++ -O3 -std=c++11 main.cpp
    

    Then, let's dump assembly:

    objdump -d a.out | c++filt > main.s
    

    The result assembly of write_vector is:

    00000000004005c0 :
      4005c0:   48 39 f7                cmp    %rsi,%rdi
      4005c3:   41 54                   push   %r12
      4005c5:   49 89 f4                mov    %rsi,%r12
      4005c8:   55                      push   %rbp
      4005c9:   53                      push   %rbx
      4005ca:   48 89 fb                mov    %rdi,%rbx
      4005cd:   74 25                   je     4005f4 
      4005cf:   84 d2                   test   %dl,%dl
      4005d1:   74 2d                   je     400600 
      4005d3:   31 ed                   xor    %ebp,%ebp
      4005d5:   0f 1f 00                nopl   (%rax)
      4005d8:   8b 13                   mov    (%rbx),%edx
      4005da:   89 ee                   mov    %ebp,%esi
      4005dc:   31 c0                   xor    %eax,%eax
      4005de:   bf a4 06 40 00          mov    $0x4006a4,%edi
      4005e3:   48 83 c3 04             add    $0x4,%rbx
      4005e7:   83 c5 01                add    $0x1,%ebp
      4005ea:   e8 81 fe ff ff          callq  400470 
      4005ef:   49 39 dc                cmp    %rbx,%r12
      4005f2:   75 e4                   jne    4005d8 
      4005f4:   5b                      pop    %rbx
      4005f5:   5d                      pop    %rbp
      4005f6:   41 5c                   pop    %r12
      4005f8:   c3                      retq   
      4005f9:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
      400600:   8b 33                   mov    (%rbx),%esi
      400602:   31 c0                   xor    %eax,%eax
      400604:   bf a8 06 40 00          mov    $0x4006a8,%edi
      400609:   48 83 c3 04             add    $0x4,%rbx
      40060d:   e8 5e fe ff ff          callq  400470 
      400612:   49 39 dc                cmp    %rbx,%r12
      400615:   75 e9                   jne    400600 
      400617:   eb db                   jmp    4005f4 
      400619:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    

    We can see, that at the begging of the function, we check the value and jump to one of two possible loops:

      4005cf:   84 d2                   test   %dl,%dl
      4005d1:   74 2d                   je     400600 
    

    Of course, this only works if a compiler is capable to detect that a condition is actual invariant. Usually, it perfectly works for flags and simple inline functions. But if the condition is "complex", consider using approaches from other answers.

提交回复
热议问题