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

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

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

什么是可能导致使用未命名的命名空间的devise注意事项? 有什么优点和缺点?

(在下文中, 直通的东西是不适用于C ++ 11的东西,但适用于C ++ 03。C ++ 11几乎没有区别(如果有的话,它们只是语言律师的分歧,我不记得))。

未命名的名称空间是一种实用程序,可以有效地将单位标识为本地翻译单元。 它们的行为就像为每个翻译单元select一个名称空间的唯一名称一样:

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

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

这意味着你可以有一个免费的函数(例如)可以存在于多个翻译单元中的帮助,而且它们不会在链接时发生冲突, 因为它们都有唯一的名字空间 。 效果与使用C中使用的static关键字几乎相同,您可以将其放入标识符声明中。 以这种方式使用的static在C ++中被弃用,因为未命名的名称空间是一种优越的替代scheme,甚至可以使types翻译单元成为本地的。

 namespace { int a1; } static int a2; 

两者都是翻译单位本地,不会在链接时发生冲突。 但不同之处在于,匿名名称空间中的a1 只是获得一个唯一的名称。 它还有外部链接,可以导出到正在创build的目标文件的符号表中。 如果你想使用它的地址作为模板参数,这变得很重要:

 template<int * ptr> struct sample { }; // OK - a1 has external linkage sample<&a1> s1; // NOT OK - translation unit locality is done by giving a2 internal linkage. sample<&a2> s2; 

模板参数必须具有外部链接,因此在这种情况下,标识符必须放入匿名名称空间。

阅读comeau-computing的优秀文章“为什么使用一个无名的命名空间而不是静态的? 。

在匿名的命名空间中有东西意味着它在本地翻译单元 (.cpp文件及其所有内容),这意味着如果另一个具有相同名称的符号被定义在别处,则不会违反一个定义规则 (ODR)。

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

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

 namespace __unique_compiler_generated_identifer0x42 { ... } using namespace __unique_compiler_generated_identifer0x42; 

这个例子显示你join的项目中的人不理解匿名命名空间:)

 namespace { const int SIZE_OF_ARRAY_X; const int SIZE_OF_ARRAY_Y; 

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

  bool getState(userType*,otherUserType*); } 

这实际上是一个悲观: getState()有外部链接。 宁愿静态链接,因为这不会污染符号表。 最好写一下

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

这里。 我陷入了同样的陷阱(标准中的文字表明文件静态不赞成使用匿名命名空间),但是在一个像KDE这样的大型C ++项目中工作,会让很多人把你的头转向正确的方向再次围绕:)

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

例如,在我的系统中,如果使用匿名命名空间(x86-64 gcc-4.6.3和-O2;下面的代码占用大约70%的运行时间,注意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; } 

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

除了“我希望这个variables,函数,类是公共的还是私人的?”之外,没有什么优势或劣势。

未命名的命名空间将类,variables,函数和对象的访问权限限制在其定义的文件中。 未命名的命名空间function类似于C / C ++中的static关键字。
static关键字将全局variables和函数的访问权限限制在定义它们的文件中。
未命名的命名空间和static关键字之间有区别,因为其中的未命名的命名空间比静态有优势。 static关键字可以用于variables,函数和对象,但不能与用户定义的类一起使用。
例如:

 static int x; // Correct 

但,

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

但是对于未命名的命名空间也是一样的。 例如,

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