Can a Declaration Affect the Std Namespace

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 namespace std. 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 namespace std 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:

  1. 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.
  2. 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.
  3. 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 namespace std, 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 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.

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



Leave a reply



Submit