Can I rely on the condition of a for loop to be re-evaluated ?

This is a discussion on Can I rely on the condition of a for loop to be re-evaluated ? within the C++ Programming forums, part of the General Programming Boards category; I'm almost certain that I can rely on it, but just to be sure... For example: Code: int main() { ...

  1. #1
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498

    Can I rely on the condition of a for loop to be re-evaluated ?

    I'm almost certain that I can rely on it, but just to be sure...
    For example:
    Code:
    int main()
    {
        srand(time(nullptr));
        std::vector<int> vi = {1,4,4,1,1};
        for(auto x = vi.begin(); x!=vi.end(); x++)
        {
            int i=rand()%6;
            if(i==1||i==4)
                vi.push_back(i);
        }
        for(auto x:vi)
            std::cout<<x<<std::endl;
    }
    It iterates over the modified vector in my case. (even after changing some compiler options manually).
    Is that standard/portable behaviour or is the compiler free to stop iterating at the original end iterator ?
    Does volatile solve anything if the later is the case ?
    Last edited by manasij7479; 05-25-2012 at 06:36 PM.
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  2. #2
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,177
    O_o

    That's almost certainly not going to be "optimized" away; it is possible I supposed, but I feel safe with that.

    That said, that's really the wrong way to go about that conceptual model; you should instead consider using an insertion iterator.

    Soma

  3. #3
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    Quote Originally Posted by phantomotap View Post
    That said, that's really the wrong way to go about that conceptual model; you should instead consider using an insertion iterator.
    This was just an example snippet.
    I'm thinking of circumstances, when actual iteration is needed and the current element is 'somehow' used.
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  4. #4
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,177
    I'm thinking of circumstances, when actual iteration is needed and the current element is 'somehow' used.
    I realize that it was an example.

    It just happens that the model here is pretty common.

    My point was that using actual iterators for iteration is usually a little better.

    Soma

  5. #5
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    Quote Originally Posted by phantomotap View Post
    My point was that using actual iterators for iteration is usually a little better.
    What ?
    Now I'm confused. :S
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  6. #6
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,177
    Now I'm confused.
    The actual loop body isn't using iterators. You are using the container directly.

    You are using iterators to control the range. That is all.

    What you are doing is equivalent to just using `std::vector<???>::size()' and a counter to control the range.

    I'm saying that actually using iterators to access and modify container elements is usually a little better.

    Soma

  7. #7
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    Quote Originally Posted by phantomotap View Post
    The actual loop body isn't using iterators. You are using the container directly.
    Code:
    for(auto x = vi.begin(); x!=vi.end(); x++)
    Err..
    x is an iterator here.
    The loop body could use *x for whatever purpose necessary.
    My question was if the evaluation of "x!=vi.end()" is mandatory for every cycle of the loop.
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  8. #8
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,177
    x is an iterator here.
    You are clearly not listening to hints so I'll just bash you over the freaking head!

    The iterator `x' may be invalidated; the instant `x' becomes invalid the code breaks. The code breaks because `x' is not an actual iterator when you've invalidated it; it is an iterator in name only; it is exactly equivalent to using a random pointer. You need to use an actual iterator.

    I'm telling you that you need to use iterators correctly. I don't know why you aren't getting that.

    *shrug*

    Maybe I should have just smacked you with it from the start.

    The model you've employed here is fine. The code is broken. It isn't broken because of the compiler optimizing out the loop condition. It is broken because you aren't using an actual iterator into the `std::vector<???>'. Every time `std::vector<???>:ush_back()' is called you may invalidate `x'. The iterator points to the old memory area owned by the `std::vector<???>'; the operation `std::vector<???>:ush_back()' may move that memory.

    So, here is what you need to do, read the documentation for every method of every container you use and see which operations may invalidate iterators. If you invalidate an iterator, you may not use it for anything.

    Soma

  9. #9
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    Got it .. :P
    I'm still in the dark about what you mean by "actual iterators".
    If the iterators is going to be invalidated when the vector's data is moved into a bigger memory area,
    isn't it just simpler using plain counter variables and a "x < vi.size()" condition to manage the loop?

    There'd be no chance of invalidated iterators then.... but I would be paranoid enough to consider x not getting updated.
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  10. #10
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,177
    There'd be no chance of invalidated iterators then.... but I would be paranoid enough to consider x not getting updated.
    Well, you would probably not have the chance of invalidating iterators, but you would of course still need to be careful.

    Take the code you posted as yet another reason why programming isn't always simple.

    If you simply swapped out the code with a counter and `std::vector<???>::size()' you might wind up with an infinite loop. The vector could grow by one every iteration triggering another iteration.

    So, changing to a counter doesn't guarantee that the code will behave reasonably and correctly.

    Using iterators, correctly mind, is usually better.

    Soma

  11. #11
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    Quote Originally Posted by phantomotap View Post
    Using iterators, correctly mind, is usually better.
    I can't think of a way to do that but "vi.begin() + counter" but that would be quite redundant as vi[counter] gets the same thing.
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  12. #12
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,177
    As always, you take examine the problem and figure out what works to solve it.

    If you understand how and when the iterators are invalidated you can easily write code to prevent these problems.

    Take this model for example, you setup your range properly and by using an insertion iterator can write very clear code for the loop body.

    Code:
    int s(rand() % 6);
    if((s==1) || (s==4))
    {
        *it++ = s;
    }
    The code to setup the range is as easy as getting the range iterators from the `std::vector<???>'.

    The code to prevent the iterators from becoming invalid is as simple as measuring the difference between the size and the capacity and adjusting the capacity for the worse case scenario.

    This assumes you need to use the original `std::vector<???>'. Using secondary storage and splicing the storage together is probably the better option in general.

    Soma

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Execution of statements in a loop condition
    By 127.0.0.1 in forum C Programming
    Replies: 4
    Last Post: 05-10-2011, 06:12 AM
  2. what condition in the while loop?
    By joeman in forum C++ Programming
    Replies: 3
    Last Post: 03-05-2010, 10:49 AM
  3. Overide for loop condition
    By erasm in forum C Programming
    Replies: 2
    Last Post: 08-11-2009, 08:08 AM
  4. need while(for(loop)) to be condition
    By thestien in forum C++ Programming
    Replies: 4
    Last Post: 10-12-2006, 08:32 AM
  5. help with loop condition
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 03-23-2002, 11:18 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21