2

I ran into a case where I had to swap out the value of a certain object. Due to my own sloppy copy and paste, I accidentally copied the type declaration as well. Here is a simplified example:

int main()
{
    int i = 42;
    cout << "i = " << i++ << endl;

    // ... much later

    if( isSwapRequired == true )
    {
        int i = 24;
        cout << "i = " << i++ << endl;
    }
    cout << "i = " << i++ << endl;
}

To my dismay, the compiler did not catch this and further went on to let i = 24 live in its own little scope. Then later, it turns out that outside the scope, i remains as 43. I noticed that if both i were in the same level, then the compiler would obligingly catch this mistake. Is there a reason for the compiler to treat the multiple declarations differently?

If it matters, I am using VS10.

Morpork
  • 551
  • 1
  • 6
  • 21

2 Answers2

8

This program is perfectly valid and correct as per rules laid out by the standard, the compiler does not need to catch anything, there is nothing to catch.

The standard allows same named variables to exist in their respective scopes and it clearly defines the rules as to which variable will be referenced when you use them in particular scope.Same named variables hide or shadow the variables at global scope.

Within in your local scope(within the conditional if block) the locally declared i hides the global i. If you need to access global i within this scope you need to use ::i.

Outside the conditional block, the only i that exists is the globally declared i.


Answer to question in comments:

Though compilers don't really have to warn of this, most compilers will provide you this diagnostic if you compile your program with highest warning level enabled or you explicitly tell the compiler to warn of this specific behavior.

For GCC, you can use -Wshadow.

-Wshadow

Warn whenever a local variable or type declaration shadows another variable, parameter, type, or class member (in C++), or whenever a built-in function is shadowed. Note that in C++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct/class/enum.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • I understand now that the compiler is working according to the standard. However, I sometimes make the mistake of naming things the same (particularly iterators, because I quickly run out of ways to spell `it` as a short form). I now wonder why not a compiler warning then, akin to a declared but unused variable? – Morpork Mar 27 '13 at 13:24
  • @Morpork: Check above, Updated to answer your question. – Alok Save Mar 27 '13 at 13:34
  • Thanks for expanding on your answer. By the way, I tried to activate all warnings with /Wall on Visual Studio 2010 but it still did not warn about this. I will just have to be careful. (I browsed a bit and found [this](http://stackoverflow.com/questions/6225070)) – Morpork Mar 27 '13 at 13:52
1

This is no multiple declaration, because each of your is has a different scope and the local scope is always in favor of the global scope.

If you want to use your i from top-level of main() use ::i.

See here for a tutorial.

bash.d
  • 13,029
  • 3
  • 29
  • 42
  • I have never learned this. I always thought the compiler would be unable to resolve which variable was being referenced. Thank you for pointing this out. – Morpork Mar 27 '13 at 13:17
  • You are welcome. This has to do with the actual machine-code behind it, look for `stackframe` if you are interested. – bash.d Mar 27 '13 at 13:18