By Herb Sutter, Andrei Alexandrescu 著
树人译
名字空间和模块
57. 把类型和其非成员函数接口放在同一个名字空间中。
非成员函数也是函数:为了能被正确地调用,被用作一个类类型X的接口的一部分的非成员函数(特别是操作符和助手函数)必须定义在X所在的名字空间中。
58. 把类型和函数放到单独的名字空间中,除非你明确地想把它们放到一起工作。
这样有助于防止名称查找意外:通过把它们放在各自的名字空间中(连同与它们直接相关的非成员函数;参见:Item57),把类型从出于无心的“实参依赖查找”(ADL,通常所说的Koenig查找)中脱离出来,并且鼓励有意的ADL。避免把一个类型和模板化的函数或操作符放在同一名字空间中。
59. 不要在头文件或#include指令前放置名字空间using指令。
名字空间using指令是为了你的方便,而不是让你与其它人相冲突:绝不要在#include指令前写using声明或指令。
推论:不要在头文件中写名字空间级的using声明或指令;作为替换,应该显式地用名字空间来限定所有名称。(第二条规则是从第一条得出的,因为头文件绝不可能知道其后有什么其他头文件的#include指令出现)
60. 避免在不同模块中分配和释放内存。
把事情后推到你发现它们的地方:在一个模块中分配内存,而在另一个不同的模块中释放内存,这样做会因为在那些模块间建立了一个微妙的长距离相关性而使你的程序变得很脆弱。它们必须使用同一个编译器版本,同样的选项flag(特别是debug和NDEBUG)和同样的标准库实现来编译,而且在实践中,在释放操作发生时分配内存的模块最好仍在加载中。
61. 不要在头文件定义具有链接的实体。
重复会导致膨胀:包括名字空间级的变量或函数在内的具有链接的实体会被分配内存。在头文件中定义如此的实体会引起连接错误或内存浪费。把所有具有链接的实体都放到实现文件中去。
62. 不要让异常跨模块边界传播。
不要把石头扔到邻居家的花园里去:现在还没有被广泛认可的关于C++异常处理的标准。不要让异常在代码的两个地方传播,除非你控制着用于构建的编译器及其选项;否则,模块可能不会支持关于异常传播的兼容性实现。典型地,归结为:不要纵容异常跨模块/子系统边界传播。
63. 在模块接口中充分使用可移植的类型。
涉及到(模块的)边界时要格外小心:不要让一个类型出现在模块的外部接口中,除非你能保证所有用户都能正确地理解这个类型。使用用户能够理解的最高级别的抽象。