开发者

How to show that a loop control variable is not changed inside the C++ for-loop body?

In C++ changing a loop variable inside a for-loop is allowed:

for( int i = 0; i < limit; i++ ) {
    if( condition ) {
       i--;
    }
}

Now if a loop body is rather complex it is not immediately obvious to the reader whether the loop variable is changed inside the loop body. It would be nice to somehow tweak the code so that once the reader only sees the for-loop header he immediately knows that the loop variable is not changed inside the body.

For example, if I use const:

const int value = computeValue();
//lots of code here

then 开发者_开发知识库it is clear that whatever code is written below the const variable definition the variable is unchanged.

Is there a way to achieve something similar - logical constness within the iteration - in case of for-loop control variables in C++?


I don't think this is possible for hand-crafted loop, but I'd guess that could be considered an additional argument to encourage the use of std::for_each and BOOST_FOREACH for iterations over STL container.

EDIT ... and the C++0x range-based for-loop (thanks Matthieu. M :)


This is a great question and got me thinking about how you might do this and ways around it. Without spending too much time, the only thing I came up with was:

int limit = 10;
for(int i(0), guard(0); i < limit; i++, guard++)
{
         // lots of code here
    assert(i == guard);
}

Obviously, the user could still modify guard in the loop, but perhaps the inention at the top shows that it is going to be checked.


Use for_each combined with boost::counting_iterator and a function that accepts a const int.

for_each(boost::counting_iterator<int>(0), boost::counting_iterator<int>(limit),
    [&](const int i)
    {
        // do something with i
    });


C++0x fun. This code is not compiled:

for (int i = 0; i < 10; ++i)
{
    [&, i] ()
    {
        if ( i == 5 )
        {
            ++i;
        }
        cout << i << endl;
    }();
}

Error: 'i': a by-value capture cannot be modified in a non-mutable lambda


There is no logical construct to enforce this. If you put ‘const int idx = i‘ as the first statement in the loop, and then only use ‘idx‘, you may be able to achieve a similar enforcing but at the loss of some clarity. Otherwise, just use comments.


You could make the entire body of the for loop a separate function, for which the loop control variable is out of scope.

I can't think of a simple way to do what you want since the loop control variable is be definition mutable, in order to control the loop.


Create a strange object with a macro that takes FILE and LINE, the latter possibly as a template parameter (is it a compile time constant?). As you increment it, it must be use the same FILE and LINE. Well the same line will probably suffice. If it is not on the same line you might get a compiler error.

template< int line > 
class Counter
{
 // stuff
public:
   bool valid() const;
   static void inc( Counter<line> & counter );  
};

for( Counter<__LINE__> counter( n ); counter.valid(); Counter<__LINE__>::inc( counter ) )
{
 // body

   // what __LINE__ do I need to use here to increment counter? Can be done but won't be
}

I haven't tested it. Just an idea.


Technically you could do e.g.

int main()
{
    for( int i = 0;  i < 42;  ++i )
    {{
        typedef void    i;

        i = 666;        // !Nope.
    }}
}

If you want access to i inside the loop body you'd then have to provide an alternate name (referring to const) before the typedef.

But I don't recommend this technical solution, because it's obscure and not common, so not obvious to reader.

Instead, just refactor big loops. :-)


You may try to change your "loop" variable name into something long and ridiculous, so that touching it inside the loop (more than once) will scratch the eye.

Also some like using dedicated loop macros, such as BOOST_FOREACH. This conceals the loop variable/iterator.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜