原因
编译器不会阅读注释(或者设计文档),很多程序员也不会(始终如一)。代码中表达的内容已定义了语义,并且(原则上)可以由编译器或者其他工具检查
示例1
typedef int Month;
class Date{
public:
Month month() const; // do
int month(); // don't
};
第一个声明的month
明确表示返回Month
以及不修改Date
对象的状态。第二个声明的month
留给读者猜测,并为未捕获的bug提供了更多可能性。
例子2
坏的示例
这个循环是std::find:
的限制形式。
void f(vector<string> & v){
string val;
cin >> val;
// ...
int index = -1; // 不好的,加应该用 gsl::index
for(int i = 0; i < v.size(); i++){
if(v[i] == val){
index = -1;
break;
}
}
// ...
}
好的示例
意图更清晰的表达应该是:
void f(vector<string> & v){
string val;
cin >> val;
// ...
auto p = find(begin(v), end(v), val); // better
// ...
}
一个设计良好的库比直接使用语言功能要表达意图要好很多
- C++程序员应该了解标准库,并且在适当的地方使用它。
- 任何程序员都应该了解正在处理的项目的基础库,并适当的使用它们。
- 使用这些准则的任何程序员都应该了解准则支持库,并适当地使用它。
例子3
change_speed(double s); // bad: s是什么意思
// ...
change_speed(2.3);
比较好的做法是明确double的含义(是新速度还是相对于就速度的变化?)和单位:
change_speed(Speed s); // better: s的含义已指定
// ...
change_speed(2.3); // error: 没有单位
change_speed(23m / 10s); // 米/秒
我们可以接受一个无修饰的double值作为变化量,但是这容易引发错误。如果即想要绝对速度,又想要速度的变化量,我们需要定义一个Delta类型。
实施建议
总的来说很难实施。
- 坚持使用
const
(检查成员函数是否修改其对象;检查函数是否修改指针或者引用传递的参数) - 重视类型转换(类型转换会使类型系统无法发挥作用)
- 检测模仿标准库的代码(困难)