C++ Unnamed/anonymous namespace(匿名命名空间)
Unnamed Namespace
什么是匿名命名空间
匿名命名空间,就是没有名字的namespace,如下所示:
#include <iostream>
namespace // unnamed namespace
{
void doSomething() // can only be accessed in this file
{
std::cout << "v1\n";
}
}
int main()
{
doSomething(); // we can call doSomething() without a namespace prefix
return 0;
}
匿名命名空间的作用
Unnamed Namespace可以限定namespace里的内容的作用域,上面的doSomething函数只可以在main.cpp里进行获取,功能很像是一个声明static的全局函数。比如说,引用别人的文件的时候,发现有个函数的定义是相同的,为了遵循One Definition Rule,就可以用匿名命名空间把自己的内容括起来。
不过为什么匿名命名空间会限定namespace里的变量的作用域呢?
这是因为,对于一个命名空间,如果它没有名字,那么默认它的作用域等同于其父命名空间的作用域。(All content declared in an unnamed namespace is treated as if it is part of the parent namespace. So even though function doSomething is defined in the unnamed namespace, the function itself is accessible from the parent namespace (which in this case is the global namespace), which is why we can call doSomething from main without any qualifiers)
在我理解来看,每一个cpp,或者说每一个Translation Unit,其本身就是一个namespace,叫做global namespace。Translation Unit里面的非静态全局变量和类会在Linker阶段被认作是通用的变量,而其他的像static global variables或匿名命名空间里的内容都认作namespace里的私有成员。
Static vs Unnamed Namespace
unnamed namespace与static globals非常像,比如上面所说的代码跟下面的代码功能是一样的:
#include <iostream>
static void doSomething() // can only be accessed in this file
{
std::cout << "v1\n";
}
int main()
{
doSomething(); // we can call doSomething() without a namespace prefix
return 0;
}
既然上面说了Unnamed Namespace与static globals的作用是类似的,那么二者有何区别呢?
其区别在于:
- static需要去对每一个全局函数或变量加上static关键字,而用匿名命名函数就方便一些,直接用namespace花括号包起来就行了
- unnamed namespace优于static globals,因为前者可以作用与User-defined types,而static不行,代码如下所示:
//legal code
static int sample_function() { /* function body */ }
static int sample_variable;
//illegal code
static class sample_class { /* class body */ };
static struct sample_struct { /* struct body */ };
//legal code
namespace
{
class sample_class { /* class body */ };
struct sample_struct { /* struct body */ };
}
(Putting methods in an anonymous namespace prevents you from accidentally violating the One Definition Rule, allowing you to never worry about naming your helper methods the same as some other method you may link in. And, as pointed out by luke, anonymous namespaces are preferred by the standard over static members.)
Ps: C++03标准中明确提出了,static globals会被弃用,unnamed namespace是更好的选择,原话如下
The use of the static keyword is deprecated when declaring objects in a namespace scope; the unnamed-namespace provides a superior alternative.
而C++11的新标准中移除了这一段话,static functions现在也是标准做法,而且不会被弃用,所以只需要记住,说匿名命名空间更好只是因为它可以用于类或结构体这些user-defined type而已。