26

Why is adding names to the std namespace undefined behaviour?

The obvious answer is "because the standard says so," e.g. in C++14 [namespace.std] 17.6.4.2.1/1:

The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. ...

However, I would be really interested in the reasons for this ruling. I can of course understand adding overloads of names already in std could break behaviour; but why is adding new, unrelated names a problem?

Programs can already wreak havoc inside std with macros, which is why pretty much all standard library implementations have to consist solely of reserved names (double-underscore and starting-underscore-followed-by-capital) for all non-public parts.

I would really be interested in a situation in which something like this can be problematic:

namespace std
{
  int foo(int i)
  { return i * 42; }
}

#include <algorithm>  // or one or more other standard library headers

when this is perfectly legal and the standard library has to cope:

#define foo %%

#include <algorithm>  // or one or more other standard library headers

What is the rationale for this Undefined Behaviour?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Maybe because any specific implementation of `std` might have undocumented things in it, that might interact with things that you'd put in `std` yourself (for example, you might be defining something with a name that already exists, and then the standard can't guarantee that everything works as specified anymore). – Jesper May 31 '16 at 08:55
  • @Jesper That's what I tried to address with the macro bit - it's still perfectly legal for me to define a macro with any non-reserved name. How does this "`std` with with an undocumented `std::x`" cope with me doing `#define x %%%`? – Angew is no longer proud of SO May 31 '16 at 08:57
  • @Jesper shouldn't it be covered by trailing underscores in labels? – W.F. May 31 '16 at 08:58
  • 1
    What if you decide that you need a `vector::random_iterator`, you add it to `std`, and in the next version the wise people who make these decisions think: "Hey, let's add a `vector::random_iterator`" and make `array_shuffle` use it. – CompuChip May 31 '16 at 09:11
  • My simplistic thought would be that the idea of the `std` namespace is to standardize things, so allowing you to change it would rather defeat the point. – Mark Setchell May 31 '16 at 09:16
  • 1
    @Angew How about "A translation unit that includes a standard library header shall not `#define` or `#undef` names declared in any standard library header"? (C++11, 17.6.4.3.1). (It's not limited to documented names.) – molbdnilo May 31 '16 at 09:20
  • 2
    @sleeptightpupper: actually, the standard _does_ prohibit you from defining any of the reserved names in any shape or form. All language keywords and all names used in the standard C++ library (and a couple of generic names) _are_ reserved. – Dietmar Kühl May 31 '16 at 09:22
  • 1
    @molbdnilo It's technically not limited to documented names, but does that mean that you have to parse all of your standard library headers and find all non-public names in there before you can legally define a macro? – Angew is no longer proud of SO May 31 '16 at 09:30
  • 2
    Would there have any problem with a rule which said that extending the std:: namespace *in any way inconsistent with what a future C++ spec does* would be UB? That would allow people to adapt code written for future C++ specs by adding features to std:: that match what the new spec will implement, while also allowing compilers to add features from the new spec while still supporting the old one. – supercat Jun 02 '16 at 15:10

1 Answers1

13

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.
Eugene
  • 6,194
  • 1
  • 20
  • 31
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 1
    Excellent point about the implementation source files: I believe that's *precisely* the thing I overlooked. – Angew is no longer proud of SO May 31 '16 at 09:29
  • Though this doesn't affect the behavior of programs, an implementation *may* choose to take the standard literally. For example, `libstdc++` names one of its variables `Container c` because that's what it says in the standard, though you'd normally expect it to be uglified. – uh oh somebody needs a pupper May 31 '16 at 09:40
  • @sleeptightpupper: I don't think any of the _exposition only_ things in the standard library result in reserving names. There is probably no formal specification but I consider these declarations non-normative and, thus, the names not to be reserved. The relevant clause (17.5.2.3, [objects.within.classes]) doesn't state that explicitly but I think it is implicit in the first paragraph. – Dietmar Kühl May 31 '16 at 10:10
  • @sleeptightpupper We are talking about the container adaptors, yes? Those are `protected` members, so the name is part of the interface. – T.C. Jun 01 '16 at 15:56
  • unless otherwise specified... https://en.cppreference.com/w/cpp/language/extending_std – QuentinUK Jun 07 '20 at 09:26
  • @DietmarKühl: I do not agree with point 3. I have an example where I have to put a name into `std`. See my [question](https://stackoverflow.com/q/64214337/11279879). – Dr. Gut Oct 07 '20 at 01:42