如何在标头中使用未命名的命名空间会导致ODR违规?

时间:2014-05-14 10:33:24

标签: c++ one-definition-rule unnamed-namespace

在Google C ++样式指南中,Namespaces部分指出" 在头文件中使用未命名的命名空间很容易导致违反C ++ One Definition Rule(ODR)。"

我理解为什么在实现文件中使用未命名的命名空间会导致ODR违规,但不能在标头中使用它们。这怎么会导致违规?

2 个答案:

答案 0 :(得分:5)

原因是如果你实际上在匿名中使用任何东西 命名空间,冒着未定义的行为风险。例如:

namespace {
double const pi = 3.14159;
}

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

内联函数(以及类和模板,以及 必须在多个翻译中定义的任何其他内容 单位)是令牌必须相同(通常情况下, 除非你点击某个宏),并且所有符号都必须绑定 相同。在这种情况下,每个翻译单元都有一个单独的 pi的实例,因此pi中的twoPiR绑定到不同的const 每个翻译单位的实体。 (有一些例外, 但它们都涉及整体表达。)

当然,即使没有匿名命名空间,也是如此 这里的未定义行为(因为pi表示内部链接 默认),但基本原则成立。在标题中的任何使用 未命名的命名空间中的任何内容(或在中定义的任何const对象) 标题)可能会导致未定义的行为。无论 是一个真正的问题或不依赖,但肯定是任何事情 真的涉及上面3.14159的地址,将导致 问题。 (我在这里说“真的”,因为有很多案例 地址或参考文献正式使用的地方,但是 实践中,内联扩展将实际产生该值 正在使用。当然,令牌3.14159是{{1}} 无论它出现在哪里。)

答案 1 :(得分:0)

在test.h中

namespace {
  int x;
}

namespace{
  int x;
}

在任何源文件中包含该头文件都会导致ODR违规,因为x定义了两次。发生这种情况是因为编译器为未命名的命名空间赋予了唯一标识符,并且翻译单元中所有出现的未命名命名空间都被赋予相同的标识符。换句话说:每个TU最多只有一个未命名的命名空间。