为什么使用未命名的名称空间,它们的好处是什么?

我刚刚加入了一个新的c++软件项目,我正在试图理解设计。该项目经常使用未命名的名称空间。例如,在类定义文件中可能会出现这样的情况:

// newusertype.cc
namespace {
const int SIZE_OF_ARRAY_X;
const int SIZE_OF_ARRAY_Y;
bool getState(userType*,otherUserType*);
}


newusertype::newusertype(...) {...

可能导致使用未命名名称空间的设计考虑因素是什么?优点和缺点是什么?

161217 次浏览

在匿名命名空间中存在某个符号意味着它是这个翻译单元 (.cpp文件及其所有包含)的本地符号,这意味着如果在其他地方定义了另一个具有相同名称的符号,则不会违反一个定义规则 (ODR)。

这与C中具有静态全局变量或静态函数的方式相同,但它也可以用于类定义(并且在c++中应该使用而不是static)。

同一文件中的所有匿名名称空间都被视为相同的名称空间,不同文件中的所有匿名名称空间是不同的。匿名命名空间相当于:

namespace __unique_compiler_generated_identifer0x42 {
...
}
using namespace __unique_compiler_generated_identifer0x42;

匿名命名空间使所包含的变量、函数、类等仅在该文件中可用。在你的例子中,这是一种避免全局变量的方法。运行时或编译时性能没有差异。

除了“我想要这个变量、函数、类等是公共的还是私有的?”之外,没有太多的优点或缺点。

未命名命名空间是一个实用程序,使标识符翻译单元本地。它们的行为就像你要为命名空间的每个翻译单元选择一个唯一的名称:

namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }

使用空主体的额外步骤很重要,因此您已经可以在命名空间主体中引用该命名空间中定义的标识符,如::name,因为using指令已经发生。

这意味着你可以拥有名为help的自由函数,它们可以存在于多个翻译单元中,并且它们不会在链接时发生冲突。其效果几乎与使用C语言中使用的static关键字相同,你可以把它放在标识符的声明中。未命名的名称空间是一个更好的选择,它甚至能够使类型转换单元成为本地的。

namespace { int a1; }
static int a2;

这两个a都是翻译单元本地的,不会在链接时发生冲突。但区别在于匿名命名空间中的a1有一个唯一的名称。

在comeau-computing 为什么使用未命名的名称空间而不是静态名称空间? (Archive.org镜子)上阅读优秀的文章。

这个例子表明,你加入的项目中的人不理解匿名命名空间:)

namespace {
const int SIZE_OF_ARRAY_X;
const int SIZE_OF_ARRAY_Y;

它们不需要在匿名命名空间中,因为const对象已经具有静态链接,因此不可能与另一个翻译单元中的同名标识符冲突。

    bool getState(userType*,otherUserType*);
}

这实际上是一种悲观:getState()具有外部联系。静态链接通常更好,因为它不会污染符号表。最好还是写下来

static bool getState(/*...*/);

在这里。我也陷入了同样的陷阱(标准中有说法认为文件静态在某种程度上被弃用,而支持匿名名称空间),但是在像KDE这样的大型c++项目中工作,你会遇到很多人再次把你的想法转过来:)

除了这个问题的其他答案之外,使用匿名名称空间还可以提高性能。由于名称空间内的符号不需要任何外部链接,因此编译器可以更自由地对名称空间内的代码进行积极优化。例如,在循环中被多次调用的函数可以内联,而不会对代码大小产生任何影响。

例如,在我的系统上,如果使用匿名名称空间,以下代码将占用大约70%的运行时间(x86-64 gcc-4.6.3和-O2;注意,add_val中的额外代码使编译器不想包含它两次)。

#include <iostream>


namespace {
double a;
void b(double x)
{
a -= x;
}
void add_val(double x)
{
a += x;
if(x==0.01) b(0);
if(x==0.02) b(0.6);
if(x==0.03) b(-0.1);
if(x==0.04) b(0.4);
}
}


int main()
{
a = 0;
for(int i=0; i<1000000000; ++i)
{
add_val(i*1e-10);
}
std::cout << a << '\n';
return 0;
}

未命名命名空间限制类、变量、函数和对象对定义它的文件的访问。未命名命名空间功能类似于C/ c++中的static关键字 static关键字限制全局变量和函数对定义它们的文件的访问 未命名命名空间和static关键字之间有区别,因为未命名命名空间比静态命名空间有优势。static关键字可以用于变量、函数和对象,但不能用于用户定义的类 例如:< / p >

static int x;  // Correct

但是,

static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong

但是对于未命名的命名空间也是可能的。 例如,< / p >

 namespace {
class xyz {/*Body of class*/}
static structure {/*Body of structure*/}
} //Correct