For behaviour

  • Follow


I have finally tracked down a problem that has been bugging me for a
while, and it appears that I had been overlooking it because I was
confident that I knew what this behaviour should be...

The problem came when I tried to process my function taking an
iterator range as follows

void func(iterator begin, iterator end)
{
   for( ; begin != end; ++begin)
   {
      // do stuff
   }
}

To me this seemed sensible. I don't know where I first saw the form,
but I had been using it in VC6 (I know this is no indication of
compliance) for years with the result that i expected in that each
item between begin (included) and end (excluded).

In simple terms it is much like the loop

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

I expected j to get set to 0, then 1 then for the loop to end, but
this is not how my compiler is behaving. j first gets set to 1 and
there is only ever one pass through. i is being incremented on the
first pass. If I create an extra copy of the iterated value

for (int k = i; k != 2; ++k) ...

I get the behaviour I was anticipating.

Could anyone clear this up for me. What should the behaviour be? Is
dropping the copy bad practice?

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply rhphotography.net (2) 3/26/2010 7:34:25 AM

Richard Howard wrote:
> I have finally tracked down a problem that has been bugging me for a
> while, and it appears that I had been overlooking it because I was
> confident that I knew what this behaviour should be...
> 
> The problem came when I tried to process my function taking an
> iterator range as follows
> 
> void func(iterator begin, iterator end)
> {
>    for( ; begin != end; ++begin)
>    {
>       // do stuff
>    }
> }
> 
> To me this seemed sensible. I don't know where I first saw the form,
> but I had been using it in VC6 (I know this is no indication of
> compliance) for years with the result that i expected in that each
> item between begin (included) and end (excluded).
> 
> In simple terms it is much like the loop
> 
> int i = 0;
> for ( ; i != 2; ++i)
> {
>    int j = i;
> }
> 
> I expected j to get set to 0, then 1 then for the loop to end, but
> this is not how my compiler is behaving. j first gets set to 1 and
> there is only ever one pass through. i is being incremented on the

How do you know this? Walking through with a debugger? Inspecting
assembly instructions? I assume you are doing either of these with an
optimized build.

> first pass. If I create an extra copy of the iterated value
> 
> for (int k = i; k != 2; ++k) ...
> 
> I get the behaviour I was anticipating.
> 
> Could anyone clear this up for me. What should the behaviour be?

The behavior should be that which gives the same result as naively looping.

> Is dropping the copy bad practice?

Why would it be? We end up with the same result with many fewer
instructions and in far less time. Seems like a good thing.

Jeff

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Jeff 3/26/2010 11:32:36 AM


Richard Howard wrote:
> I have finally tracked down a problem that has been bugging me for a
> while, and it appears that I had been overlooking it because I was
> confident that I knew what this behaviour should be...
> 
> The problem came when I tried to process my function taking an
> iterator range as follows
> 
> void func(iterator begin, iterator end)
> {
>    for( ; begin != end; ++begin)
>    {
>       // do stuff
>    }
> }
> 
> To me this seemed sensible. I don't know where I first saw the form,
> but I had been using it in VC6 (I know this is no indication of
> compliance) for years with the result that i expected in that each
> item between begin (included) and end (excluded).


Let me answer your question with an integer counter first and then with
iterators.


> 
> In simple terms it is much like the loop
> 
> int i = 0;
> for ( ; i != 2; ++i)
> {
>    int j = i;
> }
> 
> I expected j to get set to 0, then 1 then for the loop to end, but
> this is not how my compiler is behaving. j first gets set to 1 and
> there is only ever one pass through. i is being incremented on the
> first pass. If I create an extra copy of the iterated value
> 
> for (int k = i; k != 2; ++k) ...
> 
> I get the behaviour I was anticipating.

This is all due to the optimization. The compiler is smart enough to see
that the body of the loop does not have any side-effects and that it's
safe to just collapse the loop to a single assignment of 1 to j;
In your second loop (with k) it all depends on what the compiler can
assume about the starting value of i. I guess that there was some code
between the loops that could modify i and in that case the compiler
can't make any assumptions about it's starting value unlike in the first
loop where all values are statically known.

Now the example with iterators is a lot more complicated. I'm actually
surprised at the outcome you describe. I can think of only one case when
the compiler could eliminate that loop and that is when iterators are
actually pointers and the body of the loop can be statically proven to
not have any side effects during each iteration.



> 
> Could anyone clear this up for me. What should the behaviour be? Is
> dropping the copy bad practice?
> 


HTH,
    Andy.

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Andy 3/26/2010 11:36:06 AM

Richard Howard <rhphotography.net@googlemail.com> wrote:
>
> I have finally tracked down a problem that has been bugging me for a
> while, and it appears that I had been overlooking it because I was
> confident that I knew what this behaviour should be...
> 
> The problem came when I tried to process my function taking an
> iterator range as follows
> 
> void func(iterator begin, iterator end)
> {
>    for( ; begin != end; ++begin)
>    {
>       // do stuff
>    }
> }
> 
> To me this seemed sensible. I don't know where I first saw the form,
> but I had been using it in VC6 (I know this is no indication of
> compliance) for years with the result that i expected in that each
> item between begin (included) and end (excluded).

Your expectation is correct, but only if neither begin nor end are
modified within the loop, and the container they are iterators of is not
modified during the loop.

> In simple terms it is much like the loop
> 
> int i = 0;
> for ( ; i != 2; ++i)
> {
>    int j = i;
> }
> 
> I expected j to get set to 0, then 1 then for the loop to end, but
> this is not how my compiler is behaving. j first gets set to 1 and
> there is only ever one pass through. i is being incremented on the
> first pass.

For the specific code above, that is acceptable behavior. The only
effect of the loop construct above is that it makes i == 2, as long as
the generated object code does that, then it is correct.

> If I create an extra copy of the iterated value
> 
> for (int k = i; k != 2; ++k) ...
> 
> I get the behaviour I was anticipating.
> 
> Could anyone clear this up for me. What should the behaviour be? Is
> dropping the copy bad practice?

Maybe if you posted more complete examples?

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 3/26/2010 11:46:03 AM

On Mar 26, 1:34 pm, Richard Howard <rhphotography....@googlemail.com>
wrote:
> I have finally tracked down a problem that has been bugging me for a
> while, and it appears that I had been overlooking it because I was
> confident that I knew what this behaviour should be...
>
> The problem came when I tried to process my function taking an
> iterator range as follows
>
> void func(iterator begin, iterator end)
> {
>    for( ; begin != end; ++begin)
>    {
>       // do stuff
>    }
>
> }
>
> To me this seemed sensible. I don't know where I first saw the form,
> but I had been using it in VC6 (I know this is no indication of
> compliance) for years with the result that i expected in that each
> item between begin (included) and end (excluded).
>
> In simple terms it is much like the loop
>
> int i = 0;
> for ( ; i != 2; ++i)
> {
>    int j = i;
>
> }
>
> I expected j to get set to 0, then 1 then for the loop to end, but
> this is not how my compiler is behaving. j first gets set to 1 and
> there is only ever one pass through. i is being incremented on the
> first pass. If I create an extra copy of the iterated value
>
> for (int k = i; k != 2; ++k) ...
>
> I get the behaviour I was anticipating.
>
> Could anyone clear this up for me. What should the behaviour be? Is
> dropping the copy bad practice?

{ edits: quoted banner removed. please keep readers in mind when quoting. -mod }

what kind of container does the iterator belong to?


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Musaul 3/26/2010 11:46:49 AM

4 Replies
127 Views

(page loaded in 0.068 seconds)

Similiar Articles:













7/25/2012 4:28:24 PM


Reply: