Scope, Lifetime and Namespaces
Scope decides where a name can be used; lifetime decides how long an object exists. Namespaces group related names so that libraries — and your own code — don't collide. Together they keep large programs organised.
Block scope and lifetime
A variable declared in a block exists from its declaration to the closing brace, and is destroyed there. For objects that own resources, destruction means cleanup — the basis of RAII (lesson 30):
#include <iostream> #include <string> #include <utility> struct Announcer { std::string name; explicit Announcer(std::string n) : name(std::move(n)) { std::cout << "create " << name << '\n'; } ~Announcer() { std::cout << "destroy " << name << '\n'; } }; int main() { Announcer outer{"outer"}; { Announcer inner{"inner"}; std::cout << "inside the block\n"; } std::cout << "after the block\n"; }
create outer create inner inside the block destroy inner after the block destroy outer
Objects are destroyed in reverse order of creation. The ~Announcer function is a destructor (lesson 32).
Static local variables
A static local variable is created once, the first time execution reaches it, and lives until the program ends:
#include <iostream> int next_ticket() { static int counter = 100; return counter++; } int main() { for (int i = 0; i < 3; ++i) std::cout << next_ticket() << ' '; std::cout << '\n'; }
100 101 102
Global variables
Variables outside any function live for the whole program and are visible everywhere in the file. Avoid mutable globals — any function can change them, making bugs hard to trace. Global constants (constexpr) are fine.
Namespaces
A namespace groups names. Code outside refers to them with :::
#include <iostream> namespace geometry { constexpr double pi = 3.14159265358979; double circle_area(double r) { return pi * r * r; } namespace imperial { double feet_to_metres(double feet) { return feet * 0.3048; } } } int main() { std::cout << geometry::circle_area(1.0) << '\n'; std::cout << geometry::imperial::feet_to_metres(10) << '\n'; }
3.14159 3.048
C++17 lets you write nested namespaces in one go: namespace geometry::imperial { … }.
using declarations and directives
| Form | Effect | Advice |
|---|---|---|
std::vector | Fully qualified name | Clearest; the usual style |
using std::vector; | Brings one name into scope | Fine in .cpp files and function bodies |
using namespace std; | Brings every name in std into scope | Avoid, and never in headers |
namespace fs = std::filesystem; | A short alias for a long namespace | Handy and safe |
Here's the kind of clash using namespace std; invites — std::count already exists:
#include <algorithm> #include <iostream> using namespace std; int count = 0; int main() { count++; cout << count << '\n'; }
main.cpp:8:5: error: reference to 'count' is ambiguous main.cpp:9:13: error: reference to 'count' is ambiguous
Anonymous namespaces
An unnamed namespace makes its contents private to the current source file — the C++ equivalent of static at file scope:
#include <iostream> namespace { int helper(int x) { return x * 2; } // invisible to other files } int main() { std::cout << helper(21) << '\n'; }
42
Lesson 48 shows how this fits into multi-file programs.
Try it yourself
Put two conversion functions in a units namespace and call them with a namespace alias.
77 F, 100 C