在Google c++风格指南中,命名空间部分指出"在头文件中使用未命名的命名空间很容易导致违反c++单一定义规则(ODR)。"
我理解为什么不在实现文件中使用未命名的名称空间会导致odr违规,但不知道在头文件中使用如何做到这一点。这怎么可能导致违规呢?
原因是,如果您实际上在匿名中使用任何东西命名空间中,您将面临未定义行为的风险。例如:
namespace {
double const pi = 3.14159;
}
inline double twoPiR( double r ) { return 2.0 * pi * r; }
内联函数(类、模板和)的规则任何其他必须在多种翻译中定义的内容单位)是令牌必须相同(通常情况下,除非你击中了一些宏),所有的符号都必须绑定相同。在这种情况下,每个翻译单元都有一个单独的pi
的实例,所以twoPiR
中的pi
结合到不同的每个翻译单元中的实体。(也有一些例外,但是它们都包含整型表达式。)
当然,即使没有匿名命名空间,这也是这里的未定义行为(因为const
表示内部链接)默认),但基本原则是成立的。的头文件中使用中定义的const对象中的任何内容头文件)可能导致未定义的行为。它是否这是一个真正的问题或不是取决于,但肯定是什么真正涉及到pi
的地址,上面,是要引起的问题。(我在这里说"真的",因为有很多情况在正式使用地址或参考的地方,但在实际上,内联展开会得到这个值被使用。当然,令牌3.14159
是3.14159
In test.h
namespace {
int x;
}
namespace{
int x;
}
在任何源文件中包含该头文件都将违反ODR,因为x
定义了两次。这是因为编译器为未命名的命名空间提供了唯一标识符,并且翻译单元中所有未命名的命名空间都被赋予了相同的标识符。换句话说:每个TU最多有一个未命名的命名空间。