当标头和实现分开时,静态或未命名的命名空间仍然有用吗?

问题描述

正如在此 question 中的回答,我了解到函数static 关键字意味着它只能从该文件中的函数中看到。我认为未命名的命名空间可以用于相同的目的。

然而,通常实现和头文件是分开的。因此,在我看来,程序员可以通过不在头文件中写入此类私有内容的声明来隐藏实现文件中的所有“私有内容”。

考虑到上述情况,static 和未命名命名空间何时有用?我能想到的唯一情况是多个实现文件对应一个文件

解决方法

在实现文件中保留定义在任何意义上都不会使其成为私有。任何其他头文件或实现文件都可以声明该函数并使用它。这并不总是坏事 - 我在真正需要的时候使用了库的部分私有实现(但我不建议这样做)。

这种不那么私密的实现更糟糕的部分是它可能违反单一定义规则。 ODR 规定每个*函数或变量在整个程序中必须只有一个定义。如果有多个定义,则行为未定义**。
这意味着,当您在文件中拥有不那么私密的实现而没有人知道时,他们可能会在不知不觉中编写具有相同名称和参数的函数并违反 ODR。

对于应该限制在单个文件中的所有自由函数,最好使用 static 或匿名命名空间。需要从其他文件使用的函数不能使用此策略,因此为了限制 ODR 违规的风险,您应该使用描述性名称和(命名)命名空间。只要确保 you don't overuse namespaces


注意:在头文件中使用匿名命名空间没有意义。匿名命名空间将其内容的范围限制在它所在的翻译单元,但头文件被复制并粘贴到(可能)多个 TU 中。匿名命名空间的一种用途是在仅头文件的库中,如 this question 中所述 - 它允许在不违反 ODR 的情况下在头文件中创建全局对象(但代价是每个 TU 都有自己的该变量副本) .


*除了模板函数、inline 函数、类定义中定义的函数等等。即便如此,所有定义也必须完全相同。

**当我遇到它时,链接器使用随机定义,以当时它看到的为准。随之而来的是欢闹和长时间的调试会话。