[英]How would use of unnamed namespaces in headers cause ODR-violations?
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). " 在Google C ++样式指南中, 命名空间部分指出“ 在头文件中使用未命名的命名空间很容易导致违反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. 我理解为什么不在实现文件中使用未命名的命名空间可能会导致ODR违规,但不能在标头中使用它们。 How can this cause a violation?
这怎么会导致违规?
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. 在这种情况下,每个翻译单元具有单独的
pi
实例,因此两个twoPiR
的pi
绑定到每个翻译单元中的不同实体。 (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. 当然,即使没有匿名命名空间,这也是未定义的行为(因为
const
默认意味着内部链接),但基本原则成立。 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. 在未命名的命名空间(或标头中定义的任何const对象)中的任何内容的标头中的任何使用都可能导致未定义的行为。 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. 它是否是一个真正的问题取决于,但肯定涉及上述
pi
的地址的任何事情都会引起问题。 (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.) (我在这里说“真的”,因为很多情况下地址或引用都是正式使用的,但实际上,内联扩展会导致实际使用的值。当然,令牌
3.14159
是3.14159
而不管它出现的地方。)
In test.h 在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. 在任何源文件中包含该头文件都会导致ODR违规,因为
x
被定义了两次。 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.
换句话说:每个TU最多只有一个未命名的命名空间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.