Is Iterator initialization inside for loop considered bad style, and why?

前端 未结 13 1439
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-05 19:37

Typically you will find STL code like this:

for (SomeClass::SomeContainer::iterator Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end         


        
相关标签:
13条回答
  • 2021-02-05 20:09

    It may make for disjointed code, but I also like to pull it out to a separate function, and pass both iterators to it.

    doStuff(coll.begin(), coll.end())
    

    and have..

    template<typename InIt>
    void doStuff(InIt first, InIt last)
    {
       for (InIt curr = first; curr!= last; ++curr)
       {
           // Do stuff
       }
     }
    

    Things to like:

    • Never have to mention the ugly iterator type (or think about whether it's const or not-const)
    • If there is gain from not calling end() on each iteration, I'm getting it

    Things to not like:

    • Breaks up the code
    • Overhead of additional function call.

    But one day, we'll have lambdas!

    0 讨论(0)
  • 2021-02-05 20:09

    I agree with Ferruccio. The first style might be preferred by some in order to pull the end() call out of the loop.

    I might also add that C++0x will actually make both versions much cleaner:

    for (auto iter = container.begin(); iter != container.end(); ++iter)
    {
       ...
    }
    
    auto iter = container.begin();
    auto endIter = container.end();
    for (; iter != endIter; ++iter)
    {
       ...
    }
    
    0 讨论(0)
  • 2021-02-05 20:10

    I don't have a particularly strong opinion one way or the other, though iterator lifetime would lean me toward the for-scoped version.

    However, readability may be an issue; that can be helped by using a typedef so the iterator type is a bit more manageable:

    typedef SomeClass::SomeContainer::iterator sc_iter_t;
    
    for (sc_iter_t Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end(); ++Iter)
    {
    }
    

    Not a huge improvement, but a bit.

    0 讨论(0)
  • 2021-02-05 20:15

    You can throw braces around the initialization and loop if you are concerned about scope. Often what I'll do is declare iterators at the start of the function and reuse them throughout the program.

    0 讨论(0)
  • 2021-02-05 20:19

    The first form (inside the for loop) is better if the iterator is not needed after the for loop. It limits its scope to the for loop.

    I seriously doubt that there is any efficiency gain either way. It can also be made more readable with a typedef.

    typedef SomeClass::SomeContainer::iterator MyIter;
    
    for (MyIter Iter = m_SomeMemberContainerVar.begin(); Iter != m_SomeMemberContainerVar.end(); ++Iter)
    {
    }
    

    I would recommend shorter names ;-)

    0 讨论(0)
  • 2021-02-05 20:20

    I don't have any console experience, but in most modern C++ compiliers either option ends up being equivilent except for the question of scope. The visual studio compilier will virtually always even in debug code put the condition comparison in an implicit temporary variable (usually a register). So while logically it looks like the end() call is being made through each iteration, the optimized compiled code actually only makes the call once and the comparison is the only thing that is done each subsiquent time through the loop.

    This may not be the case on consoles, but you could unassemble the loop to check to see if the optimization is taking place. If it is, then you can you whatever style you prefer or is standard in your organization.

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