Is there a technical reason to use > (<) instead of != when incrementing by 1 in a 'for' loop?

后端 未结 21 1875
小蘑菇
小蘑菇 2020-12-23 19:48

I almost never see a for loop like this:

for (int i = 0; 5 != i; ++i)
{}

Is there a technical reason to use >

相关标签:
21条回答
  • 2020-12-23 20:29

    I take the adjectival "technical" to mean language behavior/quirks and compiler side effects such as performance of generated code.

    To this end, the answer is: no(*). The (*) is "please consult your processor manual". If you are working with some edge-case RISC or FPGA system, you may need to check what instructions are generated and what they cost. But if you're using pretty much any conventional modern architecture, then there is no significant processor level difference in cost between lt, eq, ne and gt.

    If you are using an edge case you could find that != requires three operations (cmp, not, beq) vs two (cmp, blt xtr myo). Again, RTM in that case.

    For the most part, the reasons are defensive/hardening, especially when working with pointers or complex loops. Consider

    // highly contrived example
    size_t count_chars(char c, const char* str, size_t len) {
        size_t count = 0;
        bool quoted = false;
        const char* p = str;
        while (p != str + len) {
            if (*p == '"') {
                quote = !quote;
                ++p;
            }
            if (*(p++) == c && !quoted)
                ++count;
        }
        return count;
    }
    

    A less contrived example would be where you are using return values to perform increments, accepting data from a user:

    #include <iostream>
    int main() {
        size_t len = 5, step;
        for (size_t i = 0; i != len; ) {
            std::cout << "i = " << i << ", step? " << std::flush;
    
            std::cin >> step;
            i += step; // here for emphasis, it could go in the for(;;)
        }
    }
    

    Try this and input the values 1, 2, 10, 999.

    You could prevent this:

    #include <iostream>
    int main() {
        size_t len = 5, step;
        for (size_t i = 0; i != len; ) {
            std::cout << "i = " << i << ", step? " << std::flush;
            std::cin >> step;
            if (step + i > len)
                std::cout << "too much.\n";
            else
                i += step;
        }
    }
    

    But what you probably wanted was

    #include <iostream>
    int main() {
        size_t len = 5, step;
        for (size_t i = 0; i < len; ) {
            std::cout << "i = " << i << ", step? " << std::flush;
            std::cin >> step;
            i += step;
        }
    }
    

    There is also something of a convention bias towards <, because ordering in standard containers often relies on operator<, for instance hashing in several STL containers determines equality by saying

    if (lhs < rhs) // T.operator <
        lessthan
    else if (rhs < lhs) // T.operator < again
        greaterthan
    else
        equal
    

    If lhs and rhs are a user defined class writing this code as

    if (lhs < rhs) // requires T.operator<
        lessthan
    else if (lhs > rhs) // requires T.operator>
        greaterthan
    else
        equal
    

    The implementor has to provide two comparison functions. So < has become the favored operator.

    0 讨论(0)
  • 2020-12-23 20:32

    As you can see from the other numerous answers, there are reasons to use < instead of != which will help in edge cases, initial conditions, unintended loop counter modification, etc...

    Honestly though, I don't think you can stress the importance of convention enough. For this example it will be easy enough for other programmers to see what you are trying to do, but it will cause a double-take. One of the jobs while programming is making it as readable and familiar to everyone as possible, so inevitably when someone has to update/change your code, it doesn't take a lot of effort to figure out what you were doing in different code blocks. If I saw someone use !=, I'd assume there was a reason they used it instead of < and if it was a large loop I'd look through the whole thing trying to figure out what you did that made that necessary... and that's wasted time.

    0 讨论(0)
  • 2020-12-23 20:33

    Yes there is a reason. If you write a (plain old index based) for loop like this

    for (int i = a; i < b; ++i){}
    

    then it works as expected for any values of a and b (ie zero iterations when a > b instead of infinite if you had used i == b;).

    On the other hand, for iterators you'd write

    for (auto it = begin; it != end; ++it) 
    

    because any iterator should implement an operator!=, but not for every iterator it is possible to provide an operator<.

    Also range-based for loops

    for (auto e : v)
    

    are not just fancy sugar, but they measurably reduce the chances to write wrong code.

    0 讨论(0)
  • 2020-12-23 20:33

    And last but not least, this is called defensive programming, meaning to always take the strongest case to avoid current and future errors influencing the program.

    The only case where defensive programming is not needed is where states have been proven by pre- and post-conditions (but then, proving this is the most defensive of all programming).

    0 讨论(0)
  • 2020-12-23 20:33

    Besides the examples, where the loop variable will (unintentional) change inside the body, there are other reasions to use the smaller-than or greater-than operators:

    • Negations make code harder to understand
    • < or > is only one char, but != two
    0 讨论(0)
  • 2020-12-23 20:34

    There are several ways to write any kind of code (usually), there just happens to be two ways in this case (three if you count <= and >=).

    In this case, people prefer > and < to make sure that even if something unexpected happens in the loop (like a bug), it won't loop infinitely (BAD). Consider the following code, for example.

    for (int i = 1; i != 3; i++) {
        //More Code
        i = 5; //OOPS! MISTAKE!
        //More Code
    }
    

    If we used (i < 3), we would be safe from an infinite loop because it placed a bigger restriction.

    Its really your choice whether you want a mistake in your program to shut the whole thing down or keep functioning with the bug there.

    Hope this helped!

    0 讨论(0)
提交回复
热议问题