21 Beginner The Hundred
One Scope for Every Case
one tidy local, and the case below it stops compiling
#include <iostream>
void apply(char op, int a, int b) {
switch (op) {
case '*':
int product = a * b; // a little local, just for this case
std::cout << "product: " << product << '\n';
break;
case '+':
std::cout << "sum: " << a + b << '\n';
break;
default:
std::cout << "unknown operator\n";
}
}
Compile it. What happens?
Answer
It doesn't compile — and the error points at case '+':, a line that does nothing wrong.
Why¶
A switch has exactly one block: the braces after the condition. case '*': and
case '+': are labels inside that block — jump targets, much like goto targets — not
scopes of their own. So product is in scope from its declaration all the way to the
switch's closing brace, and jumping to case '+': or default: would enter that scope
past the initializer, leaving a live variable that was never initialized. The standard
forbids such a jump, and GCC 11.5 explains it from both ends:
Only initialization is fenced off, not visibility: drop the = a * b and
int product; compiles, with product plainly visible — and indeterminate — inside
case '+':. Reading it there is undefined behavior, though -Wall does warn:
‘product’ may be used uninitialized (-Wmaybe-uninitialized).
The fix¶
Give the case its own block — the braces cost one line and close the scope before the next label:
Takeaway: case labels are jump targets, not scopes — a switch body is one scope, so
any case that declares a variable needs its own braces.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo — add -DSHOW_BUG to meet the error.