Scopes and linkage
7.1 — Compound Statements (Blocks)¶
A compound statement (also called a block) is a group of zero or more statements treated by the compiler as a single statement.
-
Syntax: Enclosed in curly braces
{ }. -
Nesting: Blocks can be nested inside other blocks.
-
Scope: Variables defined inside a block are local to that block and are destroyed when the block ends.
7.2 — User-Defined Namespaces¶
Namespaces help prevent naming collisions by allowing you to group identifiers into a named scope.
-
Scope Resolution Operator (
::): Used to access an identifier inside a namespace (e.g.,NamespaceName::identifier). -
Nesting: You can nest namespaces inside each other.
-
Namespace Aliases: Allow you to create a shorter name for a long or nested namespace (e.g.,
namespace fb = foo::bar;).
7.3 — Local Variables¶
Local variables are defined inside a function or a block.
-
Scope: Local scope (only accessible within the block they are defined).
-
Duration (Lifetime): Automatic storage duration (created at definition, destroyed at the end of the block).
-
Linkage: No linkage (cannot be referred to by other files or even other functions).
7.4 & 7.5 — Global Variables and Shadowing¶
Global variables are defined outside of any function.
-
Scope: File scope (accessible from the point of definition to the end of the file).
-
Duration: Static duration (created when the program starts, destroyed when it ends).
-
Variable Shadowing: Occurs when a local variable has the same name as a global variable. The local variable "hides" the global one within that local scope. You can still access the global version using the global scope resolution operator (e.g.,
::value).
7.6 & 7.7 — Internal and External Linkage¶
Linkage determines whether multiple declarations of an identifier refer to the same object.
-
Internal Linkage: The identifier can be used anywhere within the file it is defined, but it is invisible to other files.
-
Keyword:
static(for non-const globals). -
Note:
constandconstexprglobals have internal linkage by default.
-
-
External Linkage: The identifier can be seen and used by other files in the project.
-
Keyword:
extern. -
Forward Declaration: To use an external variable in another file, you must provide a forward declaration using
externwithout an initializer.
-
7.8 — Why (Non-Const) Global Variables are Evil¶
While tempting, non-const global variables are generally considered bad practice:
-
State Unpredictability: Any function can change the variable, making it hard to track where a bug originated.
-
Coupling: Functions become dependent on the global state, making them harder to move to other projects or test in isolation.
-
Concurrency: They make multi-threaded programming much more difficult.
7.9 & 7.10 — Inline Functions and Variables¶
The inline keyword has evolved from a performance hint to a tool for managing definitions across multiple files.
-
Inline Functions/Variables: Can be defined in multiple files (usually via a header) without violating the One Definition Rule (ODR), provided the definitions are identical.
-
Sharing Constants: The modern way to share global constants is to put
inline constexprvariables in a header file. This gives you the best of both worlds: a single source of truth and no "duplicate definition" errors.
7.11 — Static Local Variables¶
Using the static keyword on a local variable changes its duration but not its scope.
-
Behavior: The variable is initialized only the first time the function is called. It "remembers" its value between function calls.
-
Lifetime: It lasts for the entire duration of the program, even though it can only be seen inside the function.
7.12 — Scope, Duration, and Linkage Summary¶
| Property | Local Variable | Global Variable | Static Local |
|---|---|---|---|
| Scope | Block Scope | File Scope | Block Scope |
| Duration | Automatic | Static | Static |
| Linkage | None | Internal or External | None |
7.13 — Using Declarations and Directives¶
-
Using Declaration: Brings a specific name into the current scope (e.g.,
using std::cout;). Safest way to avoid prefixing. -
Using Directive: Brings the entire namespace into the current scope (e.g.,
using namespace std;).- Warning: Avoid
using namespace std;in the global scope or in header files, as it significantly increases the risk of naming collisions.
- Warning: Avoid
7.14 — Unnamed and Inline Namespaces¶
-
Unnamed Namespaces: All identifiers inside are treated as having internal linkage (effectively replaced the
statickeyword for functions/globals). -
Inline Namespaces: Often used for versioning. Identifiers in an inline namespace are treated as if they are part of the parent namespace, allowing for seamless library updates.