- Learn C++ - https://www.learncpp.com -

2.9 — Naming conflicts and the std namespace

Let’s say you are driving to a friend’s house for the first time, and the address given to you is 245 Front Street in Mill City. Upon reaching Mill City, you pull up your map, only to discover that Mill City actually has two different Front Streets across town from each other! Which one would you go to? Unless there were some additional clue to help you decide (e.g. you remember his house is near the river) you’d have to call your friend and ask for more information. Because this would be confusing and inefficient (particularly for your mailman), in most countries, all street names and house addresses within a city are required to be unique.

Similarly, C++ requires that all identifiers be non-ambiguous. If two identical identifiers are introduced into the same program in a way that the compiler or linker can’t tell them apart, the compiler or linker will produce an error. This error is generally referred to as a naming collision (or naming conflict).

An example of a naming collision

a.cpp:

main.cpp:

When the compiler compiles this program, it will compile a.cpp and main.cpp independently, and each file will compile with no problems.

However, when the linker executes, it will link all the definitions in a.cpp and main.cpp together, and discover conflicting definitions for function myFcn. The linker will then abort with an error. Note that this error occurs even though myFcn is never called!

Most naming collisions occur in two cases:
1) Two (or more) definitions for a function (or global variable) are introduced into separate files that are compiled into the same program. This will result in a linker error, as shown above.
2) Two (or more) definitions for a function (or global variable) are introduced into the same file (often via an #include). This will result in a compiler error.

As programs get larger and use more identifiers, the odds of a naming collision being introduced increases significantly. The good news is that C++ provides plenty of mechanisms for avoiding naming collisions. Local scope, which keeps local variables defined inside functions from conflicting with each other, is one such mechanism. But local scope doesn’t work on functions. So how do we keep function names from conflicting with each other?

The std namespace

When C++ was originally designed, all of the identifiers in the C++ standard library (including std::cin and std::cout) were available to be used without the std:: prefix. However, this meant that any identifier in the standard library could potentially conflict with any name you picked for your own identifiers. Code that was working might suddenly have a naming conflict when you #included a new file from the standard library. Or worse, programs that would compile under one version of C++ might not compile under a future version of C++, as new identifiers introduced into the standard library could have a naming conflict with already written code. So C++ moved all of the functionality in the standard library into a special area called a namespace.

In C++, a namespace is a grouping of identifiers that is used to reduce the possibility of naming collisions. It turns out that std::cout‘s name isn’t really std::cout. It’s actually just cout, and std is the name of the namespace that identifier cout is part of. In modern C++, all of the functionality in the C++ standard library is now defined inside namespace std (short for standard).

Back to our address analogy for a moment, having two Front Streets was only problematic because those streets existed within the same city. If there was a Front Street in two different cities, there would be no issue (so long as you knew which city you were looking for Front street in). Namespaces function like the cities do in this analogy.

The key useful property of a namespace is that identifiers defined inside a namespace won’t conflict with identically named identifiers defined outside of the namespace. For example, std::cout wouldn’t conflict with some foo::cout that was defined inside a namespace named foo, or some other cout that didn’t have a namespace at all.

We’ll talk more about namespaces in a future lesson and also teach you how to create your own. For now, the only thing you really need to know about namespaces is that whenever we use an identifier (like cout) that is part of the standard library, we need to tell the compiler that that identifier lives inside the std namespace.

Key insight

When you use an identifier that is defined inside a namespace (such as the std namespace), you have to tell the compiler that the identifier lives inside the namespace.

Explicit namespace qualifier std::

The most straightforward way to tell the compiler that we want to use cout from the std namespace is by explicitly using the std:: prefix. For example:

This is the safest way to use cout, because there’s no ambiguity about which cout we’re referencing (the one in the std namespace).

Best practice

Use explicit namespace prefixes to access identifiers defined in a namespace.

Using namespace std (and why to avoid it)

Another way to access identifiers inside a namespace is to use a using directive statement. Here’s our original “Hello world” program with a using directive:

A using directive tells the compiler to check a specified namespace when trying to resolve an identifier that has no namespace prefix. So in the above example, when the compiler goes to determine what identifier cout is, it will check both locally (where it is undefined) and in the std namespace (where it will match to std::cout).

Many texts, tutorials, and even some compilers recommend or use a using directive at the top of the program. However, used in this way, this is a bad practice, and highly discouraged.

Consider the following program:

The above program doesn’t compile, because the compiler now can’t tell whether we want the cout function that we defined, or the cout that is defined inside the std namespace.

When using a using directive in this manner, any identifier we define may conflict with any identically named identifier in the std namespace. Even worse, while an identifier name may not conflict today, it may conflict with new identifiers added to the std namespace in future language revisions. This was the whole point of moving all of the identifiers in the standard library into the std namespace in the first place!

Warning

Avoid using directives (such as using namespace std;) at the top of your program. They violate the reason why namespaces were added in the first place.

We’ll talk more about using statements (and how to use them responsibly) in lesson 4.3c -- Using statements [1].


2.10 -- Introduction to the preprocessor [2]
Index [3]
2.8 -- Programs with multiple code files [4]