Namespaces
Namespaces exist because names are a shared, finite resource, like phone numbers in a country. Here's the same idea from a few angles.
Imagine a school where there are two students named “Alex.” The teacher can’t say just “Alex” — is it Alex Smith or Alex Chen? Everyone needs a disambiguator: the family name.
That’s it. A namespace is a family name for a set of names.
namespace graphics { void draw(); } // graphics::draw
namespace physics { void draw(); } // physics::draw
draw alone is ambiguous — same name, two different functions, just like two Alexes. graphics::draw and physics::draware the family names. Nothing about the functions changed; only how you address them.
The real world mostly solved this too. The OS has std::chrono::milliseconds and boost::chrono::milliseconds. Both people are named Milliseconds.
The :: is the separator, not the address
A full path looks like a URL:
std :: vector < int >
↑ ↑ ↑
area family the name
code name
:: is just a separator meaning “look inside.” And critically, it means search only here, not “search this and then search upward.” Compare:
std::vector — exactly this one thing, no ambiguity, ever
using namespace std; — “assume anything unresolved might be in std” — you’re guessing
** How this connects to containers**
This is the part that trips people up, so it’s worth being precise.
A container is a template. A template is a name that produces a family of types. So vector is a type name that lives inside a namespace, which is why it always arrives with its family name attached:
std::vector<int> a; // std::vector<int> + variable name a
std::map<std::string, std::vector<int>> b; // namespaces nest
no problem
Three things glued together, and the reason the middle one is namespaced is that containers are the most reimplemented thing in the language. Every library has a vector, a map, a set, a string, a queue. Nobody agreed on one, so everyone namespace-protected theirs and the pre-committee solution was the std:: prefix.
So when you see std::vector<int>, read it as: “the vector from the standard library’s family of containers, holding int.” Drop std:: and you’ve told the compiler nothing about which vector.
The part that surprises people
Namespaces are erased. They exist only during compilation. At runtime a std::vector<int> and a my::vector<int>are just two types, with no trace of their namespace in memory, in the binary, or in a debugger.
Consequence: you can’t “look inside” a namespace at runtime, and namespaces can’t be opened, closed, or changed. They’re purely a compile-time naming convention. This is why using namespace std; is often criticized — it’s a source-level shortcut that changes how the compiler resolves names, never what the program does.