Each variable exists in a region of the program where the variable name is known.
This region is known as its scope.
If an inner scope defines a variable with the same name as a variable in an outer scope, then the variable in the inner scope hides the other one. This practice is called shadowing.
Most variables you declare inside a function have block scope.
They are visible from the point of declaration through the end of the closest enclosing curly brace block.
#include <iostream>
int main()
{
int x{10};
{
int y{20};
std::cout << x << ' '
<< y << '\n';
}
// std::cout << y << '\n';
std::cout << x << '\n';
}
A variable placed within an inner block is created when the inner block starts and destroyed when it ends.
After the closing brace, its name is no longer in scope, so trying to use it results in a compile error.
Variables that are defined in the outer block are still accessible inside the nested block, but they will be hidden if the inner block declares another variable with the same name.
If you declare a new variable with the same name as a variable that exists in an outer scope, then the new variable hides the outer one.
#include <iostream>
int main()
{
int value{100};
{
int value{200};
std::cout << value << '\n';
}
std::cout << value << '\n';
}
In the nested block, the shared name refers to the nested variable.
The outer variable is still there, but its name is temporarily hidden.
When the inner block ends, the outer name becomes visible again.
Shadowing is allowed, but it usually makes code harder to understand.
The reader needs to remember which variable is currently referred to by a name.
It is possible to declare a variable outside of a loop in order to store a result to be used throughout a function.
If a variable with the same name is declared inside the loop, it will shadow the outer variable.
#include <iostream>
int main()
{
int total{0};
// Increment the value before the expression uses it
for (int i{0}; i < 3; ++i)
{
int total{i * 10};
std::cout << "Inner total: "
<< total
<< '\n';
}
std::cout << "Outer total: "
<< total
<< '\n';
}
Changes made to the inner variable do not change the outer variable because they are separate objects.
The programmer might have wanted to update the outer variable but created a new variable inside the loop.
The outer value does not change, and it is easy to miss the mistake during a quick scan of the code.
I try to avoid shadowing in almost every situation.
Writing a different name for the inner variable unambiguously reveals the programmer's intent.
Exercise: Variable Scope and ShadowingStarter code, hints and solutionOpenClose
Practice: Variable Scope and Shadowing
Work through the mission, reveal hints only when needed, and compare your result with the model solution.
Your challenge
Change the inner total initializer from i * 10 to i * 20. Predict all inner totals and the final outer total.
Mission checklist
- Run the starter as a baseline, then predict the change requested in Your challenge.
- Make that change in your editor; use the lesson-specific hints if you need help.
- Compile and run your answer, then compare with the worked solution and explain the result.
Starter program
This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.
#include <iostream>
int main()
{
int total{0};
// Increment the value before the expression uses it
for (int i{0}; i < 3; ++i)
{
int total{i * 10};
std::cout << "Inner total: "
<< total
<< '\n';
}
std::cout << "Outer total: "
<< total
<< '\n';
}Hints
There are two variables named total. The declaration inside the loop creates a new inner total on each iteration; it does not assign to the outer one.
Make two columns for the two totals. Changing i * 10 changes the inner values only, so check which declaration the final output statement can see.
Worked solution
The inner initializer now multiplies i by 20, producing inner totals 0, 20, and 40. That inner declaration shadows the outer total; the final outer total is still 0.
#include <iostream>
int main()
{
int total{0};
// Increment the value before the expression uses it
for (int i{0}; i < 3; ++i)
{
int total{i * 20};
std::cout << "Inner total: "
<< total
<< '\n';
}
std::cout << "Outer total: "
<< total
<< '\n';
}
Example output
Inner total: 0
Inner total: 20
Inner total: 40
Outer total: 0
0 comments
No comments yet. Be the first.