3.5. Namespaces¶
When we introduced functions, we noted that all functions are by default global.
Another way of saying this is that they are by default in the global namespace.
The namespace
keyword provides a mechanism
to avoid polluting the global namespace with too many names.
A namespace
is simply a named block that defines a scope.
Namespaces provide a method for preventing name conflicts in large projects.
Symbols declared inside a namespace block are placed in a named scope that prevents them from being mistaken for identically-named symbols in other scopes.
Multiple namespace blocks with the same name are allowed. All declarations within those blocks are declared in the named scope.
// declare some things in the mesa namespace
namespace mesa {
int i = 0;
double pi = 3.1416;
void details (char);
}
void mesa::details (char c) { // define the function declared earlier
// do something
}
//void mesa::oops () { // error: oops not yet declared in mesa namespace
//}
namespace mesa { // a separate mesa namespace block
void oops ();
namespace cisc {
double pi = 3.14159265358979; // not the same variable as mesa::pi
}
}
int main () {
using mesa::cisc::pi;
pi = 3.f;
mesa::details('a');
}
The larger your project, the more important it is to partition the global namespace.
By default, all symbols are declared in the global namespace (::
).
What is the problem with the global namespace?
There is only 1 of them
Name conflicts can be common on large projects
Complicates mixing third party libraries
Well-behaved third party libraries will not put much (if anything) in the global namespace.
You can put anything in a namespace, except main
.
The function main has a few special rules and one is that it must be in the global namespace.
The using
directive allows all the names in a namespace to be used
without the namespace-name as an explicit qualifier.
Use a using directive in an implementation file (i.e. *.cpp
)
if you are using several different identifiers in a namespace;
if you are just using one or two identifiers,
then consider a using declaration to only bring those identifiers into scope
and not all the identifiers in the namespace.
If a local variable has the same name as a namespace variable,
the namespace variable is hidden.
It is an error to have a namespace variable with the same name as a global variable.
3.5.1. Prefer using declarations to using namespace std
¶
What’s wrong with using namespace std;
?
Nothing, technically. It was a simplification in your first semester classes. The intent was to avoid ‘burdening’ you with having to care about this technical detail.
BUT
The using-directive using namespace std;
at any namespace scope introduces
every name from the namespace std into the global namespace
(since the global namespace is the nearest namespace that contains both std and any user-declared namespace),
which may lead to undesirable name collisions.
This, and other using directives are generally considered bad practice at file scope of a header file.
Additionally, shadowing names in the standard namespace can lead to unexpected behaviors.
It can be hard to remember every name that might be
imported when using namespace std;
.
Even when only 1 header is included.
The following example seems innocent enough,
until you learn that showpoint is a name
in std::ios
Run the following example twice,
first as is, then remove the line bool showpoint = true;
:
Errors using namespace directives are seldom this obviously wrong.
Here is a simplification of a real question asked on stack overflow:
This code compiles and runs and says the answer is: 0 1 -1 0
.
I think we can all agree that is not the correct answer for two points (0,0)
and (100,100)
.
Try This!
What is wrong with the program?
Can you fix it?
Hint:
This section is about namespaces.
One final word from two experts:
Summary
Namespace usings are for your convenience, not for you to inflict on others: Never write a
using
declaration or ausing
directive before an#include
directive.Corollary: In header files, don’t write namespace-level using directives or using declarations; instead, explicitly namespace-qualify all names. (The second rule follows from the first, because headers can never know what other header
#include
might appear after them.)Discussion
In short: You can and should use namespace using declarations and directives liberally in your implementation files after
#include
directives and feel good about it. Despite repeated assertions to the contrary, namespaceusing
declarations and directives are not evil and they do not defeat the purpose of namespaces. Rather, they are what make namespaces usable.—Herb Sutter and Andrei Alexandrescu, C++ Coding Standards
More to Explore
From: cppreference.com: namespace declarations and namespace aliases
From stack overflow: Why is using namespace std considered bad practice?