Why is including "using namespace" into a header file a bad idea in C++?
Asked Answered
O

4

32

While reading from Bruce Eckel's "Thinking in C++" about namespaces, I encountered the following statement:

However you'll virtually never see a using directive in a header file (at least not outside of scope). The reason is that using directive eliminate the protection of that particular namespace, and the effect last until the end of current compilation unit. If you put a using directive (outside of a scope) in a header file, it means that this loss of "namespace protection" will occur within any file that include this header, which often mean other header files.

Would you please like to help me to comprehend the above statement with some easy example?

Octan answered 2/2, 2011 at 8:50 Comment(1)
Yeap, here you go: #2153425Rik
T
36

Consider this program:

line#
    1 #include <string>                                                               
    2                                                                                 
    3 using namespace std;                                                            
    4                                                                                 
    5 struct string { const char* p; };  // Beware: another string!
    6                                                                                 
    7 int main()                                                                      
    8 {                                                                               
    9     string x; // Error: ambiguous - which string is wanted?
   10 }

If you try to compile it, you'll see errors:

g++     using.cc   -o using
using.cc: In function `int main()':
using.cc:9: error: use of `string' is ambiguous
using.cc:5: error:   first declared as `struct string' here
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/stringfwd.h:60: error:
   also declared as `typedef struct std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::string' here
using.cc:9: error: `string' was not declared in this scope
using.cc:9: error: expected `;' before "x"

The problem here is that when main() specifies string x;, the compiler's not sure whether the user-defined ::string or included std::string is wanted.

Now imagine you take the top part of the program... lines 1 through 5 - up to and including the struct string... and put it into a header file which you then #include before main(). Nothing changes: you still have an error. So, just as for standalone programs, header files with using statements in them can cause trouble for other code that includes them, making some of their statements ambiguous.

It can be a bigger pain though, as headers can be included - directly or indirectly - by arbitrarily huge amounts of dependent code, and...

  • removing the using statement from the header, or
  • a change to the contents of <string>, or any other header affecting std::

...might break code including the problematic header. Either problem may render dependent code uncompilable, and issues may not even be noticed until another compilation is attempted. Further, the person suffering due to the using statement may not have filesystem/code-repository permissions, corporate authority etc. to remove the using statement from the header, nor fix other affected client code.

That said, if a header only has "using" inside a class or function, then there's no affect on code beyond that scope, so the potential impact of changes to std:: is dramatically reduced.

Teneshatenesmus answered 2/2, 2011 at 9:12 Comment(0)
O
18

If a header contains using namespace std, everything from that namespace is added the global namespace in every module that includes the header.

This means you can never declare a function or define a class with the same name (and compatible parameters for a function) as an std function/class in the global namespace in any of those modules.

Outfight answered 2/2, 2011 at 8:54 Comment(1)
"you can never declare a function or define a class with the same name" - you can actually, it's just that the caller has to disambiguate usage, and in doing so the global version is matched preferentially by ::identifier, while the "used" version must be accessed like ::std::identifier. Interestingly, if there is no ambiguity, the explicit ::identifier does find the "used" version, so your "everything from that namespace is added [to] the global" is the right perspective... it's more than just a secondary implicit search location for identifiers without a :: prefix....Teneshatenesmus
B
7

Copy the following paragraph from "C++ Primer, fifth edition":

Code inside headers ordinarily should not use using declarations. The reason is that the contents of a header are copied into the including program’s text. If a header has a using declaration, then every program that includes that header gets that same using declaration. As a result, a program that didn’t intent to use the specified library name might encounter unexpected name conflicts.

Backsight answered 22/6, 2013 at 18:44 Comment(0)
T
4

Well, what is the point of using namespaces. It is to avoid the risk of name collisions.

Let's say that you have some pretty common class name, for example FooBar. If you use several libraries, there is the risk that FooBar in library A collides with FooBar in library B. For that we use two different namespaces A and B, to move the FooBars from global namespace to A::FooBar and B::FooBar (so they are kept separate from each other).

If you then put using A; and using B; in headers, this will then move A::FooBar and B::FooBar to just FooBar, bringing back the collision, removing the gain from using namespaces in the first place.

Tor answered 2/2, 2011 at 9:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.