How to Access a Local Variable in Outer Scope in C++

Is there any way to access a local variable in outer scope in C++?

You can declare a new reference as an alias like so

int main (void)
{
int v = 2; // local
int &vlocal = v;
{
int v = 3; // within subscope
cout << "local: " << vlocal << endl;
}
}

But I would avoid this practice this altogether. I have spent hours debugging such a construct because a variable was displayed in debugger as changed because of scope and I couldn't figure out how it got changed.

How can I use local variable in another scope in C++?

There is no way to accomplish that. The language does not provide a way to differentiate between the first var in main from the second var.

If you ever write production code, please refrain from using such variables. It will lead to buggy code. You will be confused about which variable is in scope in a given line of code.

Accessing variables with the same name at different scopes

No you can't, a (2) is hidden.

Ref: 3.3.7/1

A name can be hidden by an explicit
declaration of that same name in a
nested declarative region or derived
class (10.2).

Ref: 3.4.3/1

The name of a class or namespace
member can be referred to after the ::
scope resolution operator (5.1)
applied to a nested-name-specifier
that nominates its class or namespace.
During the lookup for a name preceding
the :: scope resolution operator,
object, function, and enumerator names
are ignored. If the name found is not
a class-name (clause 9) or
namespace-name (7.3.1), the program is
ill-formed.

What does local variables at the outermost scope of the function may not use the same name as any parameter mean?

The outermost scope of the function is the block that defines the function's body. You can put other (inner) blocks inside that, and declare variables in those which are local to that block. Variables in inner blocks can have the same name as those in an outer block, or the function parameters; they hide the names in the outer scope. Variables in the outer block can't have the same name as a function parameter.

To demonstrate:

void f(int a)           // function has a parameter
{ // beginning of function scope
int b; // OK: local variable
{ // beginning of inner block
int a; // OK: hides parameter
int b; // OK: hides outer variable
} // end of inner block
int a; // Error: can't have same name as parameter
}

Accessing variables in an enclosing scope(not global) hidden by local declaration in C++?

This is unfortunately not possible. Compiler warning options, like -Wshadow for GCC, can help avoiding such situations:

-Wshadow


Warn whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance
variable (in Objective-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. Same as
-Wshadow=global.

In your example, for instance, you'd get a warning like:

: In function 'int main()':

:7:9: error: declaration of 'i' shadows a previous local
[-Werror=shadow]

7 |     int i = 5;

|

As @L. F. points out in a comment below, you can use references to still have access to the other i:

#include <iostream>

int main() {
int i = 10;
if (1) {
int& nonlocal_i = i; // just before shadowing
int i = 5;
std::cout << "Local i: " << i << std::endl;
std::cout << "Main's i: " << nonlocal_i << std::endl;
}
return 0;
}

But -Wshadow will still complain, and if you were going the extra mile to find an alternative name, you could just name the local i differently.


Note:
As user4581301 points out in a comment, code like int& i = i; doesn't do what you'd expect in an inner scope:

#include <iostream>

int main()
{
int i = 4;
{
int& i = i;
std::cout << i;
}
}

It tries to use the variable i to initialize itself. In Microsoft's compiler you get a compilation error like:

error C4700: uninitialized local variable 'i' used

In GCC, if you turn all the warnings on, you get this message:

error: reference 'i' is initialized with itself [-Werror=init-self]

But it silently compiles and does the wrong thing if you don't have the warnings turned on

C++, Accessing a non-global variable declared inside other method

This is undefined behavior: once the function finishes, accessing a variable inside it by pointer or reference makes the program invalid, and may cause a crash.

It is perfectly valid, however, to access a variable when you go "back" on the stack:

void assign(int* ptr) {
*ptr = 1234;
}
int main() {
int kek = 5;
cout << kek << endl;
assign(&kek);
cout << kek << endl;
}

Note how assign has accessed the value of a local variable declared inside another function. This is legal, because main has not finished at the time the access has happened.

Is it well defined to access a variable from an outer scope before it is redefined?

Is this well defined or it just happened to work?

It is well-defined. The scope of a variable declared inside a {...} block starts at the point of declaration and ends at the closing brace. From this C++17 Draft Standard:

6.3.3 Block scope      [basic.scope.block]

1     A name declared in a block (9.3) is local to that
block; it has block scope. Its potential scope begins at its point of
declaration (6.3.2) and ends at the end of its block. A variable
declared at block scope is a local variable.


This code compiles with no warnings in gcc-11

That surprises me. The clang-cl compiler (in Visual Studio 2019, 'borrowing' the /Wall switch from MSVC) gives this:

warning : declaration shadows a local variable [-Wshadow]

Using both -Wall and -Wpedantic in GCC 11.2 doesn't generate this warning; however, explicitly adding -Wshadow does give it. Not sure what "general" -Wxxx switch GCC needs to make it appear.

Accessing shadowed variables from inner scope

You cannot just simply achieve this as the inner variable just overshadows your outer scope variable.

If an inner block declares a variable with the same name as the variable declared by the outer block, then the visibility of the outer block variable ends at the point of the declaration by inner block.

However, if you still need to achieve this, you can do something to store the variable values in a stack that saves the variable values per scope. This is something similar to what is done during function calls (just a revised version to store only variable you require).

I would still suggest you to instead use a separate name for variables as this reduces readability of code.



Related Topics



Leave a reply



Submit