Each block defines its own scope region. So what happens when we have a variable inside a nested block that has the same name as a variable in an outer block? When this happens, the nested variable “hides” the outer variable in areas where they are both in scope. This is called name hiding or shadowing.
Shadowing of local variables
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <iostream> int main() { // outer block int apples { 5 }; // here's the outer block apples { // nested block // apples refers to outer block apples here std::cout << apples << '\n'; // print value of outer block apples int apples{ 0 }; // define apples in the scope of the nested block // apples now refers to the nested block apples // the outer block apples is temporarily hidden apples = 10; // this assigns value 10 to nested block apples, not outer block apples std::cout << apples << '\n'; // print value of nested block apples } // nested block apples destroyed std::cout << apples << '\n'; // prints value of outer block apples return 0; } // outer block apples destroyed |
If you run this program, it prints:
5 10 5
In the above program, we first declare a variable named apples
in the outer block. This variable is visible within the inner block, which we can see by printing its value (5
). Then we declare a different variable (also named apples
) in the nested block. From this point to the end of the block, the name apples
refers to the nested block apples
, not the outer block apples
.
Thus, when we assign value 10
to apples
, we’re assigning it to the nested block apples
. After printing this value (10
), nested block apples
is destroyed. The existence and value of outer block apples
is not affected, and we prove this by printing the value of outer block apples
(5
).
Note that if the nested block apples
had not been defined, the name apples
in the nested block would still refer to the outer block apples
, so the assignment of value 10
to apples
would have applied to the outer block apples
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> int main() { // outer block int apples{5}; // here's the outer block apples { // nested block // apples refers to outer block apples here std::cout << apples << '\n'; // print value of outer block apples // no inner block apples defined in this example apples = 10; // this applies to outer block apples std::cout << apples << '\n'; // print value of outer block apples } // outer block apples retains its value even after we leave the nested block std::cout << apples << '\n'; // prints value of outer block apples return 0; } // outer block apples destroyed |
The above program prints:
5 10 10
When inside the nested block, there’s no way to directly access the shadowed variable from the outer block.
Shadowing of global variables
Similar to how variables in a nested block can shadow variables in an outer block, local variables with the same name as a global variable will shadow the global variable wherever the local variable is in scope:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> int value { 5 }; // global variable void foo() { std::cout << "global variable value: " << value << '\n'; // value is not shadowed here, so this refers to the global value } int main() { int value { 7 }; // hides the global variable value until the end of this block ++value; // increments local value, not global value std::cout << "local variable value: " << value << '\n'; foo(); return 0; } // local value is destroyed |
This code prints:
local variable value: 8 global variable value: 5
However, because global variables are part of the global namespace, we can use the scope operator (::) with no prefix to tell the compiler we mean the global variable instead of the local variable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> int value { 5 }; // global variable int main() { int value { 7 }; // hides the global variable value ++value; // increments local value, not global value --(::value); // decrements global value, not local value (parenthesis added for readability) std::cout << "local variable value: " << value << '\n'; std::cout << "global variable value: " << ::value << '\n'; return 0; } // local value is destroyed |
This code prints:
local variable value: 8 global variable value: 4
Avoid variable shadowing
Shadowing of local variables should generally be avoided, as it can lead to inadvertent errors where the wrong variable is used or modified. Some compilers will issue a warning when a variable is shadowed.
For the same reason that we recommend avoiding shadowing local variables, we recommend avoiding shadowing global variables as well. This is trivially avoidable if all of your global names use a “g_” prefix.
Best practice
Avoid variable shadowing.
![]() |
![]() |
![]() |
The result of below code is:
local variable value: 8
global inside local: 5
global variable value: 4
The outcome of below code is:
local variable value: 8
global inside local: 4
global variable value: 4
Difference lines of code are
and
. You mentioned that problem in CH-5.4 . But I dont understand in that code why they behave different although value variable decreased before
--prefix returns the new value of the variable.
postfix-- returns the old value of the variable.
This isn't a problem, that's what the operators are meant to do.
Beware of the following codes:
If you are going to suppose that this code snippet is going output: 10, 11, 11; you are wrong. The actual out is as follows:
My inference is that apple is newly defined inside nested block which has different memory address than the outer block's apple, but this newly defined apple is destroyed at the end of the nested block thus no relationship with the outer block's apple. Indeed nested block apple had no relationship with outer block after it was defined inside nested block. [Please correct me if I am wrong]
Now look at this code:
Now this snippet of code works as expected. And this code snippet returns as the following:
Your first snippet of code is creating a new variable "apple" (using copy assignment I think) inside the nested block that hides (or shadows) "apple" in the outer block. The second snippet doesn't create a new variable, it assigns a new value (11) to the "apple" already initialized in the outer block.
This is a good example of what this page of the tutorial is talking about! :)
Hello,
Where do warnings show up in visual studio?
Hi Alex, Nascardriver,
I see that the local variable gets destroyed at the end of main() as it was defined here, but also the program ends at the completion of main, so I am assuming global variables also get destroyed at the ned of the last brace. Am I correct?
I have to say it from some mountaintop so I'll pick this one as its where I ended up right after the epiphany. I've been coding for 30 years, mostly pascal and java, and have just now finally realized that the ++ in C++ is a play on x++. --Me.
Yeah. Also a fun realization is that if the language were created now, it probably would have been named ++C to be compliant with best practices. :)
Nice!!!
According to some veteran programmer on youtube C# is named so because a ++ over another ++ looks like a #. So, C# = C++++ ...
Hey nascardriver
Found an inconsistency with the best practices that I wanted to report. In the second source code, "apples" is initialized using direct initialization instead of brace initialization.
thanks, fixed!
Hello, and thank you very much for all of your hard work in providing this invaluable resource for many folks who wish to learn about programming.
Is there any specific circumstance that variable shadowing would actually be useful?
I suppose with quite the complex program, with many different variables and calculations etc., and program control flow also being quite complex, I might be able to think of a case.
Many thanks!
Luke
Imagine what might happen if you didn't have shadowing -- a variable added to an outer scope could cause inner scopes (that you hadn't touched) to stop compiling. So it's useful in that context in that you don't have to make sure new outer scope additions don't have naming conflicts with inner scope variables.
Ah yes. I see that this feature is very useful for program construction.
What about local variable shadowing? Are there any specific fields of computer programming that make use of it? Have you ever run into a circumstance where you found it useful?
I've never found a proactive reason to use it.
Hi Alex or nascardriver. Can you guys please explain to me why the output is 6 in the below code?
The inner `j` shadows the outer `j`. Your code is equivalent to
Thanks nascardriver. So that is why the output in the end is 6?
Well, you start at with sum=0, then you increase it 3 * 2 times. 3 * 2 is 6. The inner loop runs 2 times for each iteration of the outer loop, which runs 3 times.