Can a declaration affect the std namespace?
The language specification allows implementations to implement <cmath>
by declaring (and defining) the standard functions in global namespace and then bringing them into namespace std
by means of using-declarations. It is unspecified whether this approach is used
20.5.1.2 Headers
4 [...] In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (6.3.6) of the namespacestd
. It is unspecified whether these names (including any overloads
added in Clauses 21 through 33 and Annex D) are first declared within the global namespace scope and are then injected into namespacestd
by explicit using-declarations (10.3.3).
Apparently, you are dealing with one of implementations that decided to follow this approach (e.g. GCC). I.e. your implementation provides ::abs
, while std::abs
simply "refers" to ::abs
.
One question that remains in this case is why in addition to the standard ::abs
you were able to declare your own ::abs
, i.e. why there's no multiple definition error. This might be caused by another feature provided by some implementations (e.g. GCC): they declare standard functions as so called weak symbols, thus allowing you to "replace" them with your own definitions.
These two factors together create the effect you observe: weak-symbol replacement of ::abs
also results in replacement of std::abs
. How well this agrees with the language standard is a different story... In any case, don't rely on this behavior - it is not guaranteed by the language.
In GCC this behavior can be reproduced by the following minimalistic example. One source file
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
Another source file
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
In this case you will also observe that the new definition of ::foo
("Goodbye!"
) in the second source file also affects the behavior of N::foo
. Both calls will output "Goodbye!"
. And if you remove the definition of ::foo
from the second source file, both calls will dispatch to the "original" definition of ::foo
and output "Hello!"
.
The permission given by the above 20.5.1.2/4 is there to simplify implementation of <cmath>
. Implementations are allowed to simply include C-style <math.h>
, then redeclare the functions in std
and add some C++-specific additions and tweaks. If the above explanation properly describes the inner mechanics of the issue, then a major part of it depends on replaceability of weak symbols for C-style versions of the functions.
Note that if we simply globally replace int
with double
in the above program, the code (under GCC) will behave "as expected" - it will output -5 5
. This happens because C standard library does not have abs(double)
function. By declaring our own abs(double)
, we do not replace anything.
But if after switching from int
with double
we also switch from abs
to fabs
, the original weird behavior will reappear in its full glory (output -5 -5
).
This is consistent with the above explanation.
scope of using declaration within a namespace
No, it is not safe - it won't pollute another namespace, but it is dangerous for other reasons:
A using
directive will import anything that is currently visible by the name you specify into the namespace where you use it. While your using
will only be visible to users of MyNamespace
, other things from "outside" will be visible to your using
declaration.
So how is this dangerous when used in a header? Because it will import things that are visible at the point of the declaration, the exact behavior will depend on the order of headers you include before the declaration (There might be different things visible from boost::numeric::ublas::vector
). Since you cannot really control which headers are included before your header (nor should you be! headers should be self-sufficient!), this can lead to very strange problems where your function will find one thing in one compilation unit, and another in the next.
As a rule of thumb, using
declarations should only be used after all includes in a .cpp file. There's also an item on this exact issue in the book "C++ Coding Standards" by Sutter and Alexandrescu (Item 59). Here's a quote:
But here's the common trap: Many people think that using declarations issued at namespace level (...) are safe. They are not. They are at least as dangerous, and in a subtler and more insidious way.
Even when it's unlikely that the name you are using
doesn't exist anywhere else (as is probably the case here), things can get ugly: In a header, all declarations should be fully qualified. This is pain, but otherwise, strange things can happen.
Also see Migrating to Namespaces, Using-declarations and namespace aliases and Namespace Naming for examples and the problem described in-depth.
What's the purpose of declaring namespace std {}?
That's a forward declaration of a namespace. You are not allowed to 'use' a namespace before it has been declared, so the declaration is necessary if you don't have any includes that bring in any part of 'std' beforehand.
Is it actually useful or necessary... That's doubtful. If you are including anything that brings in any part of std, you don't need the forward declaration. And if you are not, you don't need that using namespace std
. So it might be a bit of boilerplate code - someone who was taught to 'always write using namespace std
', and writes it even if it doesn't make any sense.
What are the reasons that extending the std namespace is considered undefined behavior?
Here are a few reasons:
- Even if names in headers have to be uglified to avoid interactions with macros, this requirement does not exist for name in the source files actually implementing the code. If an implementation does use
::std::foo(int)
as part of its implementation it would be a violation of the one definition rule. - The standard is expected to grow. If names could be added to namespace
std
any name added to the standard C++ library would be a likely breaking change. To some extent this is already true in the sense that any such name could be a macro but it is considered acceptable to break those. - There is actually no need to add names to namespace
std
: they can be added to arbitrary other namespace, i.e., even if the motivations given above are not particular strong, the restriction isn't considered to matter in any form. ...and if there is a reason to add a name to namespacestd
, it clearly does affect the behavior.
Why is including using namespace into a header file a bad idea in C++?
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 affectingstd::
...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.
What's the scope of the using declaration in C++?
When you #include a header file in C++, it places the whole contents of the header file into the spot that you included it in the source file. So including a file that has a using
declaration has the exact same effect of placing the using
declaration at the top of each file that includes that header file.
Ordering of using namespace std; and includes?
A perhaps interesting data point. When I compile the following:
using namespace std;
using namespace no_such_namespace;
with g++ 4.5.2, I get:
c.cpp:2:17: error: ‘no_such_namespace’ is not a namespace-name
c.cpp:2:34: error: expected namespace-name before ‘;’ token
To be clear, those two lines are the entire source file I compiled.
Neither std
nor no_such_namespace
has been defined as a namespace at that point, but g++ complains only about the second. I don't think there's anything special about the identifier std
in the absence of a declaration of it. I think @James Kanze is right that this is a bug in g++.
EDIT: And it's been reported. (5 years ago!)
UPDATE: Now it's more than 8 years, and still hasn't been assigned to anyone, much less fixed. g++ 4.9.2 exhibits the problem. clang++ 3.5 doesn't, but it issues a warning for std
and a fatal error for no_such_namespace
:
c.cpp:1:17: warning: using directive refers to implicitly-defined namespace 'std'
using namespace std;
^
c.cpp:2:17: error: expected namespace name
using namespace no_such_namespace;
^
1 warning and 1 error generated.
UPDATE: As of 2021-09-24, the bug report is still open and the bug exists in g++ 11.2.0. A comment posted 2021-07-24 suggests that g++ should warn about this.
Why is using namespace std; considered bad practice?
Consider two libraries called Foo and Bar:
using namespace foo;
using namespace bar;
Everything works fine, and you can call Blah()
from Foo and Quux()
from Bar without problems. But one day you upgrade to a new version of Foo 2.0, which now offers a function called Quux()
. Now you've got a conflict: Both Foo 2.0 and Bar import Quux()
into your global namespace. This is going to take some effort to fix, especially if the function parameters happen to match.
If you had used foo::Blah()
and bar::Quux()
, then the introduction of foo::Quux()
would have been a non-event.
Related Topics
What's the Best Way to Check If a File Exists in C++? (Cross Platform)
Dereferencing a Pointer When Passing by Reference
Check the File-Size Without Opening File in C++
In Lambda Functions Syntax, What Purpose Does a 'Capture List' Serve
Window C/C++ Crypto API Examples and Tips
C++ Push Multiple Types Onto Vector
Findchessboardcorners Cannot Detect Chessboard on Very Large Images by Long Focal Length Lens
Cross-Platform Iteration of Unicode String (Counting Graphemes Using Icu)
Compile Lua Code, Store Bytecode Then Load and Execute It
Why Aren't Copy Constructors "Chained" Like Default Constructors and Destructors
"Apientry _Twinmain" and "Winapi Winmain" Difference
C++ Stl: Array VS Vector: Raw Element Accessing Performance
Getting a Directory Name from a Filename