原因
除非表明了代码的意图(通过命名和注释),否则很有必要告知代码是否做了它计划做的事
例子
gsl::index i = 0;
while (i < v.size()) {
// ... do something with v[i] ...
}
这里没有表达只是循环v
中元素的意图。下标的执行细节是暴露的(所以可能被误用),而且i
的生命周期超过了循环作用域,这可能是也可能不是本意,读者不能从这段代码中推断出来。
更好的表达:
for (const auto& x : v) { /* do something with the value of x */ }
现在,这里没有明确提到迭代机制,而且循环操作是对元素的const
引用,这保证了误修改不会发生。如果想要修改,这样:
for (auto& x : v) { /* modify x */ }
对于for语句的更多细节,参考ES.71。有时还可以更清晰,使用命名算法。例如使用范围技术规范(Ranges TS)中的for_each
因为它直接表明了意图:
for_each(v, [](int x) { /* do something with the value of x */ });
for_each(par, v, [](int x) { /* do something with the value of x */ });
最后一个变体清晰地表明我们对v
中元素的处理顺序不感兴趣。
程序员应该熟悉:
- 准则支持库
- ISO C++标准库
- 当前工程中使用的任意基本库
注意
替代表达:说应该做什么,而不是仅仅表达这个应该怎样做
注意
一些语言结构比其他语言更能表达意图
例子
如果两个int
意图去表示一个二维点,这样:
draw_line(int, int, int, int); // obscure
draw_line(Point, Point); // clearer
补充
寻找有更好替代的常见模式:
- 简单的
for
循环替代为范围for
循环 f(T*, int)
接口替代为f(span<T>)
接口- 循环变量作用域过大
- 暴露的
new
和delete
- 具有许多内置类型参数的函数
还有很大的空间对程序进行智能和半自动化的转换