在Google C ++样式指南中,Namespaces部分指出" 在头文件中使用未命名的命名空间很容易导致违反C ++ One Definition Rule(ODR)。"
我理解为什么不在实现文件中使用未命名的命名空间会导致ODR违规,但不能在标头中使用它们。这怎么会导致违规?
答案 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最多只有一个未命名的命名空间。