Introduction
A local variable in C++ is any variable defined within a function (or block).
This sounds simple, but it is one of the most important ideas in C++. Where you declare a variable determines where it can be used, how long it exists, and when its resources are released.
Three things to take away:
- A local variable is local because of where it is declared, not because of its type.
- Local variables have block scope: they are only visible inside the block that declares them.
- Ordinary local variables have automatic storage duration: they are created and destroyed automatically.
Local variables are type-agnostic
It does not matter whether the variable is a fundamental type (int, double), a standard library type (std::string, std::unique_ptr), or a user-defined type (class, struct). If it is declared inside a function, it is local.
void print_x()
{
int x{10}; // local variable
std::cout << x << '\n';
}
void create_expenses()
{
std::array<double, 12> expenses {}; // local variable
}
struct Coordinate
{
int x {};
int y {};
};
void create_coordinate()
{
Coordinate s{1, 11}; // local variable
}
// All variables are local, despite having completely different types.
Thus, despite being an introductory topic, local variables are used everywhere in a codebase. Additionally, where a variable is defined determines it’s scope and duration.
Local variables have local/block scope
Local variables have local scope, meaning:
- They are only accessible within the block in which they are declared
- They are do not exist outside that block
void example()
{
int outer{100};
{
int inner{200};
std::cout << outer << '\n'; // Valid
std::cout << inner << '\n'; // Valid
}
std::cout << outer << '\n'; // OK
std::cout << inner << '\n'; // ERROR: inner is out of scope
}
This is useful because it limits where a variable can be accessed. A smaller scope means fewer places where the variable can be accidentally modified.
Local variables have local duration
Local variables exist for the duration of the function their defined in. In the example below, Logger is created when main() executes. The object goes out of scope when main() exits.
#include <iostream>
struct Logger
{
Logger() { std::cout << "Constructed\n"; }
~Logger() { std::cout << "Destroyed\n"; }
};
int main()
{
Logger log; // constructed here
} // destroyed here
// Output
Constructed
Destroyed
This is the foundation of important C++ idioms like RAII (Resource Acquisition Is Initialization).
RAII means an object acquires a resource during construction and releases it during destruction.
The resource might be:
- Memory
- A file handle
- A mutex lock
- A socket
A simple example is std::unique_ptr:
#include <memory>
void createResource(){
auto value { std::make_unique<int>(42) };
} // memory is released here
The std::unique_ptr is local. When it goes out of scope, its destructor runs and releases the owned memory.
Ultimately
A local variable is defined by where it is declared, not by what type it has.
Declare variables in the smallest scope that needs them.
Local scope is used to restrict access of local variables, reducing their visibility to other parts of the program. This prevents accidental access to variables that shouldn’t be touched.
Local duration means resources (memory, file handles, locks) are released automatically when a function returns, even if an exception is thrown.