1

I am reading Stroustrup's book and he recommends we keep variables used inside loops, only inside the scope of the loop. This is easy to do for one variable but for more variables there are more options to do it, but I am not sure is it worth it. Do you guys bother with this at all?

For example:

for (double d; is >> d;) {}

it is better to keep the variable d inside the loop scope rather than do this:

double d;
for (;is >> d;) {}
user3111311
  • 6,153
  • 5
  • 29
  • 40
  • well, this is very opinion based, but I struggle to see why you would trust anyone here more than the mighty Stroustrup. I certainly follow this advice most of the time. – RichardPlunkett Dec 26 '13 at 13:24
  • @RichardPlunkett: I can't see any opinions here. Making variables as local as possible is *per se* always good. If you can't do it (because you need the variable later or because of multiple variable wit different types), they you can't (no choice, no opinion). It might lead to too long initialization clauses, which is ugly and then different people would weight it differently. But this weighting is a different question. – maaartinus Feb 14 '14 at 23:24

7 Answers7

3

In general the smaller the scope is, the better.

There are three main reasons for this rule:

  1. Who is reading the code is not distracted trying to understand where the life of the variable will end. Using local variables you can skip over sections of code being sure that in the part skipped nothing you are interested in happened. If instead you use a variable that is not local and reuse it later who is reading must check if any of the code in the middle is using the variable.

  2. When maintaining the program you're free to change the code without worrying that code that follows it may stop working because was dependent on a variable. Suppose you've a loop and is using a variable that is not local and then you change that loop with a call to a function... the risk is that code following the original loop was depending on the value of the index.

  3. Compilers today are quite smart, but sometimes it's confusing even for them if you keep long lifespans for variables. As a result register allocation may suffer from this and the compiled code can be less efficient.

If in a function you want to do a step of processing that needs some locals but this step depends on a lot of context and it's not easy to factor it out in a function (because you'd need to pass a lot of parameters) then just open a block for the locals:

... code before ...
{
   int local1, local2;
   ... processing here ...
}
... code after ...

This is very readable and allows maintaining the smallest possible scope.

6502
  • 104,192
  • 14
  • 145
  • 251
1

Keeping variables in the smallest possible scope is worthwhile, and can avoid problems with name collisions, shadowing, etc. But it's hard to give complete general guidance because code like your example:

for (double d; is >> d;)

Is not likely to be found in the wild. I have done something like this though:

for (string s; getline(is, s); )

And there's a version using "if" which is handy:

if (MyThing* t = dynamic_cast<MyThing*>(o))

That gives you access to t within the conditional's body, but not outside, which is sort of nice because outside it would be null anyway.

John Zwinck
  • 207,363
  • 31
  • 261
  • 371
0

generally you should always keep those variables in the scope of the loop.

cageman
  • 315
  • 2
  • 10
0

well, this is very opinion based, but I struggle to see why you would trust anyone here more than the mighty Stroustrup. I certainly follow this advice most of the time.

If you put it in outside, like the second option, it means you can access the value after the loop. Thus sometimes you need to do that.

Since later access is the advantage of outside declaration, it is also slightly implied that you intend to this this when you use outside declaration, implying things that aren't true is bad, so if you dont use the values later, dont declare them outside.

RichardPlunkett
  • 2,958
  • 11
  • 14
  • So it is just matter of need and style? One way or the other is not better in terms of performance? – user3111311 Dec 26 '13 at 13:27
  • limiting scope can help the compiler make better guesses when optimizing, but there is no other upside for performance, and even that one is unlikely to have effect. – RichardPlunkett Dec 26 '13 at 13:29
  • Locally scoped means you get destroyed earlier too, which again can make a few tiny changes to performance, but not enough to care about normally. – RichardPlunkett Dec 26 '13 at 13:31
0

There are a few points to this:

  1. It improves the compilers ability to optimise, because variables that no longer are in scope doesn't need to be considered. However, modern compilers are pretty good at "following" variables and understanding when things can be optimised and when not from this.
  2. The reader of the code doesn't need to worry about "is this variable used in the following lines after the loop".
  3. The construction/desctruction of variables when they are used inside a loop may create extra overhead if the loop isn't entered. Likewise for the case of if/else statements, of course.

I think point #2 is the most important - if I can see how the variable is used for its lifetime in a short piece of code, that is really helpful.

Mats Petersson
  • 119,687
  • 13
  • 121
  • 204
0

If you want to use the loop variable outside the loop then define it outside otherwise keep those variables in the scope of the loop.

user3134167
  • 275
  • 1
  • 2
  • 10
  • Yes that is good principle, the problem is making it happen can be ugly, especially initializing more variables of different type. You can't do it in the for loop. – user3111311 Dec 26 '13 at 13:31
0

An interesting idiom I've used, especially in the context of iterators, is the usage of the comma operator for multiple values that need to be bound into a for scope:

for(vector<int>::iterator iter = foo.begin(), end = foo.end(); iter != end; ++iter)

I used this technique to avoid repeating the type definition, but it is equally well served in allowing scope capture that is much prettier.

With C++11 auto semantics, this becomes even prettier:

for(auto iter = foo.begin(), end = foo.end(); iter != end; ++iter)

As for performance, this allow even the simplest of compilers (for example, tccp) to correctly optimize variable reuse (important in embedded systems or when no optimizations are on).

Alice
  • 3,822
  • 2
  • 22
  • 28