每周技巧 #103:标志就是全局变量
本节阅读量:本文翻译自 Abseil 官网的 Tip of the Week #103: Flags Are Globals。
在 .cc 文件的全局作用域定义 flag。最多在对应的 .h 文件中声明一次。
为什么要在头文件中声明东西?
对我们大多数人来说,使用头文件是一种本能,所以我们可能已经忘了为什么使用它们:
- 在头文件中声明某个东西,方便在别处
#include。整个程序会看到同一个声明。 - 在定义同一实体的
.cc中包含这个头文件,可以确保定义与声明匹配。 - 头文件充当包 public API 的文档。使用包的 public API 之外的任何东西都不是好风格。
- 包含头文件,而不是重新声明实体,有助于工具和人类进行依赖分析。
Abseil Flags 和其他全局变量一样脆弱
你可以错误地这样做,而且不会产生链接期错误。首先,在一个 .cc 文件中放入:
|
|
然后,在另一个 .cc 文件(也许是测试)中放入下面这个错误的 flag 声明:
|
|
这个程序是病式的,任何发生的事情都是未定义行为的结果。在我的测试程序中,这段代码可以编译、链接,但在访问 flag 时崩溃。
建议
像设计全局变量一样设计命令行 flag。
- 如果可以,避免使用 flag。见 技巧 #45。
- 如果你使用 flag 是为了让测试更容易写,而且完全没有在生产中设置它的意图,请考虑给你的类添加仅测试 API。
- 考虑把 flag 当作 private static 变量处理。如果其他包需要访问它们,请用函数包装。
- 在全局作用域定义 flag,而不是在命名空间中定义,这样当 flag 名称冲突时可以得到链接错误。
- 如果一个 flag 在多个文件中访问,请在一个与其定义对应的
.h文件中声明它。 - 使用
ABSL_FLAG(type, ...)宏定义 flag。
结论
flag 是全局变量。请谨慎使用它们。像使用和声明任何其他全局变量一样使用和声明它们。
本节目录