7

In the Google C++ Style Guide, the Namespaces section states that "Use of unnamed namespaces in header files can easily cause violations of the C++ One Definition Rule (ODR)."

I understand why not using unnamed namespaces in an implementation file can cause ODR-violations, but not how use in a header can do so. How can this cause a violation?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
boycy
  • 1,473
  • 12
  • 25
  • 1
    Their style guide contains also other "intresting" advices as to avoid rvalue references, exceptions, lambdas, std::function/bind and probably many more that only they know why... – PlasmaHH May 14 '14 at 10:39
  • 6
    The Google C++ Style Guide is not exactly renowned for being particularly useful or good advice... – Cody Gray - on strike May 14 '14 at 10:39
  • I agree with you both, but that's not what I'm asking. Would the close voter care to offer a reason? – boycy May 14 '14 at 11:15
  • 2
    The reason they offered is that this question is "primarily opinion-based". That might be generally true of this *type* of question, but I strongly disagree with the close voter. I don't think it's true of *this* question. You're asking something that can be answered quite objectively, that much is very clear from the title. I think it's a fine question. – Cody Gray - on strike May 14 '14 at 11:18
  • Thanks Cody; that's a fair assessment. – boycy May 14 '14 at 11:22
  • 2
    @PlasmaHH It's hard to imagine anyone trying to write portable code using rvalue references, lambdas or `std::function/bind` today. (Not so long ago, the same thing could be said of templates; I don't know if it's still the case, but the last time I looked, the Mozilla guidelines banned them, except in the hands of a few privileged people who knew exactly how to work around the differences in the various compilers---even today, it's easy to write template code which has different semantics in VS and g++.) – James Kanze May 14 '14 at 11:37

2 Answers2

7

The reason is that if you actually use anything in the anonymous namespace, you risk undefined behavior. For example:

namespace {
double const pi = 3.14159;
}

inline double twoPiR( double r ) { return 2.0 * pi * r; }

The rule for inline functions (and classes, and templates, and anything else which must be defined in multiple translation units) is that the tokens must be identical (normally the case, unless you hit some macro), and that all symbols must bind identically. In this case, each translation unit has a separate instance of pi, so the pi in twoPiR binds to a different entity in each translation unit. (There are a few exceptions, but they all involve integral expressions.)

Of course, even without the anonymous namespace, this would be undefined behavior here (since const means internal linkage by default), but the basic principle holds. Any use in a header of anything in an unnamed namespace (or any const object defined in the header) is likely to cause undefined behavior. Whether it is a real problem or not depends, but certainly anything which really involves the address of pi, above, is going to cause problems. (I say "really" here, because there are many cases where the address or a reference is formally used, but in practice, the inline expansion will result in the value actually being used. And of course, the token 3.14159 is 3.14159 regardless of where it appears.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • James none of that really answers the question, it just describes how a name in an unnamed namespace would result in a separate instance of that object per TU, which doesn't relate to the ODR. As your code exemplifies, putting a const object in an unnamed namespace in a header doesn't make sense, but that wasn't my question. The question of how an unnamed namespace can lead to an ODR violation was answered perfectly by Rakibul. – boycy May 14 '14 at 12:23
  • 2
    @boycy Except that it does lead to undefined behavior. See the example: the function `twoPiR` has undefined behavior. This is certainly the motivation of the rule in the Google coding guidelines (and Rakibul's answer has nothing to do with unnamed namespace). – James Kanze May 14 '14 at 12:51
  • 2
    Agh. Your answer is interesting and has certainly given me a deeper understanding of the nuances of this, and why Google might've made the rule, so thank you for that. It doesn't answer my question though, which is not about Google's rationale, it's about the ODR violation. – boycy May 14 '14 at 13:12
  • The ODR violation is that `twoPiR` has two different definitions (ODR says that inline functions may only be defined more than once if both definitions are identical). The definitions are different because one uses `file1::pi` and one uses `file2::pi`. – M.M May 15 '14 at 01:25
  • @boycy My explication is the usual reason why using unnamed namespace is banned in headers. I can't speak for Google, but this has been the justification for the rule (which has been in every coding guidelines I've seen since namespaces were introduced) in the coding guidelines I've used. – James Kanze May 15 '14 at 08:27
  • Great info; doesn't change the fact that it doesn't answer the actual question. I don't really know how to make this any clearer... – boycy May 15 '14 at 12:46
  • @boycy The question asked why unnamed namespaces in the header (as opposed to elsewhere) might cause a violation of the one definition rule. My code snippet here is a typical example of a violation of the one definition rule which results from using an unnamed namespace _in a header_ which would _not_ cause a problem in a source file. – James Kanze May 15 '14 at 15:14
  • Agh, sorry, I completely misunderstood. Being too busy and getting distracted by the mentions of Google. Switching accepted answer as it has improved my understanding much more (sorry & thanks @Rakibul). – boycy May 15 '14 at 16:20
2

In test.h

namespace {
  int x;
}

namespace{
  int x;
}

Including that header file in any source file will case ODR violation, since x is defined twice. This occurs because an unnamed namespace is given a unique identifer by the compiler, and all occurrences of an unnamed namespace in a translation unit are given the same identifier. To paraphrase: every TU has at most one unnamed namespace.

boycy
  • 1,473
  • 12
  • 25
Rakib
  • 7,435
  • 7
  • 29
  • 45
  • Thanks Rakibul - I didn't realise the multiple unnamed namespaces are given the same unique name within a TU. – boycy May 14 '14 at 11:16
  • This is silly. Drop the anonymous namespaces, and you have exactly the same problem. – James Kanze May 14 '14 at 11:20
  • 4
    That was my initial thought James, however the bit of information I was missing may be the exact reason unnamed namespaces are thought to be more of a risk here: if a majority of people are unaware that multiple unnamed namespace blocks in the same TU are actually the *same* unnamed namespace, then they may not instinctively see the ODR-violation in Rakibul's example, as I didn't. – boycy May 14 '14 at 11:29
  • But that's still irrelevant to the question. Multiple namespaces with the same name are the same namespace, period. `std::vector` is in the same namespace as `std::list`, even though they are in totally different header files, and almost certainly in separate `namespace std {...}` blocks. – James Kanze May 14 '14 at 11:33
  • 1
    @boycy And the real issue, of course, is the undetected cases of violations of the ODR. The above requires a compiler diagnostic. – James Kanze May 14 '14 at 11:34
  • @James I think I've misunderstood you - when you say 'this is silly' to what are you referring? PlasmaHH - preferable of course that it doesn't compile, but as James says ODR-violations are not required to be diagnosed. – boycy May 14 '14 at 12:18
  • @boycy Generally, to the fact that it almost certainly has nothing to do with the motivation of the Google rule (which sounds like it is concerned with undefined behavior, not cases which require a diagnostic). More generally, it doesn't argue against anonymous namespaces, since they are irrelevant; you have the same problem with named namespaces, or the global namespace. – James Kanze May 14 '14 at 12:49
  • Indeed the same occurs with named namespaces - but that was the crucial bit of information I was missing, so the hole in my understanding was precisely specific to unnamed namespaces. – boycy May 14 '14 at 13:05
  • @JamesKanze, the question was how unnamed namespace can cause violation of ODR, and it could be shown with the above silly example. Obviously there are infinitely many other ways to violate ODR, but this is not the point. – Rakib May 14 '14 at 13:09
  • I've edited your answer Rakibul to emphasise the information I was missing; @James - hopefully this shows why I thought this was specific to unnamed namespaces. – boycy May 14 '14 at 13:16
  • @boycy But it has nothing to do with the reasons Google ban unnamed namespaces in header files. – James Kanze May 14 '14 at 14:13
  • No, but as I keep having to reiterate to you, my question was not "Why do Google ban this?", it was "How would this cause ODR violations?". – boycy May 14 '14 at 15:32