当前位置:主页   - 电脑 - 程序设计 - C/C++
C++ 工程实践(1):慎用匿名 namespace
来源:网络   作者:   更新时间:2012-02-10
收藏此页】    【字号    】    【打印】    【关闭

匿名 namespace (anonymous namespace 或称 unnamed namespace) 是 C++ 的一项非常有用的功能,其主要目的是让该 namespace 中的成员(变量或函数)具有独一无二的全局名称,避免名字碰撞 (name collisions)?一般在编写 .cpp 文件时,如果需要写一些小的 helper 函数,我们常常会放到匿名 namespace 里?muduo 0.1.7 中的 muduo/base/Date.cc 和 muduo/base/Thread.cc 等处就用到了匿名 namespace?

我最近在工作中遇到并重新思考了这一问题,发现匿名 namespace 并不是多多益善?

C 语言的 static 关键字的两种用法

C 语言的 static 关键字有两种用途:

1. 用于函数内部修饰变量,即函数内的静态变量?这种变量的生存期长于该函数,使得函数具有一定的“状态”?使用静态变量的函数一般是不可重入的,也不是线程安全的?

2. 用在文件级别(函数体之外),修饰变量或函数,表示该变量或函数只在本文件可见,其他文件看不到也访问不到该变量或函数?专业的说法叫“具有 internal linkage”(简言之:不暴露给别的 translation unit)?

C 语言的这两种用法很明确,一般也不容易混淆?

C++ 语言的 static 关键字的四种用法

由于 C++ 引入了 class,在保持与 C 语言兼容的同时,static 关键字又有了两种新用法:

3. 用于修饰 class 的数据成员,即所谓“静态成员”?这种数据成员的生存期大于 class 的对象(实体 instance)?静态数据成员是每个 class 有一份,普通数据成员是每个 instance 有一份,因此也分别叫做 class variable 和 instance variable?

4. 用于修饰 class 的成员函数,即所谓“静态成员函数”?这种成员函数只能访问 class variable 和其他静态程序函数,不能访问 instance variable 或 instance method?

当然,这几种用法可以相互组合,比如 C++ 的成员函数(无论 static 还是 instance)都可以有其局部的静态变量(上面的用法 1)?对于 class template 和 function template,其中的 static 对象的真正个数跟 template instantiation (模板具现化)有关,相信学过 C++ 模板的人不会陌生?

可见在 C++ 里 static 被 overload 了多次?匿名 namespace 的引入是为了减轻 static 的负担,它替换了 static 的第 2 种用途?也就是说,在 C++ 里不必使用文件级的 static 关键字,我们可以用匿名 namespace 达到相同的效果?(其实严格地说,linkage 或许稍有不同,这里不展开讨论了?)

匿名 namespace 的不利之处

在工程实践中,匿名 namespace 有两大不利之处:

1. 其中的函数难以设断点,如果你像我一样使用的是 gdb 这样的文本模式 debugger?

2. 使用某些版本的 g++ 时,同一个文件每次编译出来的二进制文件会变化,这让某些 build tool 失灵?

考虑下面这段简短的代码 (anon.cc):

  1: namespace   2: {   3:   void foo()   4:   {   5:   }   6: }   7:    8: int main()   9: {  10:   foo();  11: }

对于问题 1:

gdb 的<tab>键自动补全功能能帮我们设定断点,不是什么大问题?前提是你知道那个"(anonymous namespace)::foo()"正是你想要的函数?

$ gdb ./a.outGNU gdb (GDB) 7.0.1-debian(gdb) b '<tab>(anonymous namespace)         __data_start                  _end(anonymous namespace)::foo()  __do_global_ctors_aux         _fini_DYNAMIC                      __do_global_dtors_aux         _init_GLOBAL_OFFSET_TABLE_         __dso_handle                  _start_IO_stdin_used                __gxx_personality_v0          anon.cc__CTOR_END__                  __gxx_personality_v0@plt      call_gmon_start__CTOR_LIST__                 __init_array_end              completed.6341__DTOR_END__                  __init_array_start            data_start__DTOR_LIST__                 __libc_csu_fini               dtor_idx.6343__FRAME_END__                 __libc_csu_init               foo__JCR_END__                   __libc_start_main             frame_dummy__JCR_LIST__                  __libc_start_main@plt         int__bss_start                   _edata                        main(gdb) b '(<tab>anonymous namespace)         anonymous namespace)::foo()(gdb) b '(anonymous namespace)::foo()'Breakpoint 1 at 0x400588: file anon.cc, line 4.

其它资源
来源声明

版权与免责声明
1、本站所发布的文章仅供技术交流参考,本站不主张将其做为决策的依据,浏览者可自愿选择采信与否,本站不对因采信这些信息所产生的任何问题负责。
2、本站部分文章来源于网络,其版权为原权利人所有。由于来源之故,有的文章未能获得作者姓名,署“未知”或“佚名”。对于这些文章,有知悉作者姓名的请告知本站,以便及时署名。如果作者要求删除,我们将予以删除。除此之外本站不再承担其它责任。
3、本站部分文章来源于本站原创,本站拥有所有权利。
4、如对本站发布的信息有异议,请联系我们,经本站确认后,将在三个工作日内做出修改或删除处理。
请参阅权责声明