这一篇聊聊关于C++中的名称空间(namespace)。
一、避免在全局范围内使用 using namespace xxx
注意这个标题中的限定词,避免在全局范围内使用。什么意思呢?比如在头文件中,直接使用 using namespace std
之类的声明,这样是不好的。除非除非,你是最终代码用户,写一个小练习,小测试,否则都不要这么做。之前很喜欢写代码开头就写上 using namespace std
,因为可以省很多事,比写什么 cout
,endl
方便多了。后来我在写 MyTinySTL 这个项目时,最后写测试,为了方便,就用了 using namespace std
,写的时候是挺爽的,一运行就炸了。错误长的惨不忍睹,一大堆的名称冲突。当你使用了 using namespace std
的时候,就把 std
这个名称空间内的内容直接引用到了当前空间,如果跟当前空间的函数、类等重名了,那么编译就不通过了,这个就叫名称污染
。比如:
你编译它,就会得到类似不明确的符号 vector 啊,may be std::vector
or your::vector
啊之类的。当然了,这太明显了,谁都会看出来。问题就在于,我们不能把问题是否发生,寄托于我们是否能够看出来。当代码多了,文件多了,几十个几百个,上万行十万行,你确定你还记得你在哪个头文件 using 了什么东西?然后在一层一层 include 的情况下,莫名其妙的就炸掉了。所以,还是从根源上杜绝问题比较好。
刚刚说的是 namespace std,但对于其它的 namespace 而言,也是一样的。如果是你自己写的,你都尚未能保证你能避开所有重复的命名,除非你自己写个玩具中的 demo,如果是别人写的,那就更加不可控了。
其实解决办法有很多的,或者说是预防措施,又或者说,其实是一个良好的编程习惯。比起直接在全局使用 using namespace xxx
好一点的做法是:在局部声明并且只声明需要的那个部分。比如如果在某个作用域内经常要使用 std::cout
,std::endl
等,你可以这样做:
当然最好的还是在你要使用的东西前显示指定出它归属的名称空间,一来可以更清晰的知道它是来自哪里的库,二来这样写几乎放多久都不会有错。习惯成自然,养成了这个习惯,你就根本不会去想到有 using namespace xxx
这种东西了。
二、Best Practices
在 C++ Coding Standards 里,有这样一段话:
Summary
Namespace usings are for your convenience, not for you to inflict on others: Never write a using declaration or a using directive before an #include directive.
Corollary: In header files, don’t write namespace-level using directives or using declarations; instead, explicitly namespace-qualify all names. (The second rule follows from the first, because headers can never know what other header #includes might appear after them.)
Discussion
In short: You can and should use namespace using declarations and directives liberally in your implementation files after #include directives and feel good about it. Despite repeated assertions to the contrary, namespace using declarations and directives are not evil and they do not defeat the purpose of namespaces. Rather, they are what make namespaces usable.
在 C++ Coding Standards for EECS 381中 P32 有一段话:
- Follow guidelines for namespace
using
statements.
- Namespace declarations and directives.
- No namespace using declarations or directives are allowed at the top level of a header file.
- OK if scoped within an inline or member function body or a class declaration.
- In
.cpp
files,
- Place using statements only after all
#includes
.- Prefer using declarations of specific Standard Library functions or classes to using namespace
directives.- Especially in this course, prefer using declarations or directives to explicitly qualifying Standard
Library names withstd::
.
在 Google C++ Style Guide 中有一条:
You may not use a using-directive to make all names from a namespace available.
看了这几段,就胜过我千言万语了。
三、关于匿名 namespace
关于 unnamed namespace,cppreference 如是说到:
Unnamed namespaces as well as all namespaces declared directly or indirectly within an unnamed namespace have internal linkage, which means that any name that is declared within an unnamed namespace has internal linkage.
也就是说,现在,在匿名空间里的成员,具有内部链接,跟 static 没啥区别了。不过依然要注意,在同一层次中,可以有多个匿名空间,不过这些匿名空间会被整合成一个,所以不能像这样写,会报重定义:
当然在不同空间内的匿名空间,当然就是不同的啦,下面这样就可以通过了:
|
|
在 Google C++ Style Guide 中是这样说 unnamed namesapce 的:
When definitions in a
.cc
file do not need to be referenced outside that file, place them in an unnamed namespace or declare themstatic
. Do not use either of these constructs in.h
files.
Definition
All declarations can be given internal linkage by placing them in unnamed namespaces, and functions and variables can be given internal linkage by declaring themstatic
. This means that anything you’re declaring can’t be accessed from another file. If a different file declares something with the same name, then the two entities are completely independent.
Decision
Use of internal linkage in.cc
files is encouraged for all code that does not need to be referenced elsewhere. Do not use internal linkage in.h
files.
他们鼓励在实现文件中,把那些不需要外部引用的东西放进匿名空间中。陈硕大大在他的 CppPractice 中,第一个提到的就是慎用匿名空间。我觉得,对于他说的不利之处,现在来看,主要还是是第一点。因为匿名namespace里的东西是匿名的,所以万一以后有一天想引用它了,也说不准。其实还是用个具体名称,也不麻烦。对于那些实现细节,或者不希望暴露的,我还是喜欢扔进一个 namespace details {}
或者什么 namespace impl {}
里。
四、总结
总结就两点:
- 不要使用
using namespace xxx
,使用xxx::yyy
- 使用具名 namespace