voidf(vector<string>& v){ string val; cin >> val; // ... auto p = find(begin(v), end(v), val); // better // ... }
以上一行代码,便清晰明确的表达了上面 7 行代码想要表达的意图。
再比如要将标准输入的值存入内存:
1 2 3 4 5 6 7 8 9 10 11 12
int sz = 100; int* p = (int*) malloc(sizeof(int) * sz); int count = 0; // ... for (;;) { // ... read an int into x, exit loop if end of file is reached ... // ... check that x is valid ... if (count == sz) p = (int*) realloc(p, sizeof(int) * sz * 2); p[count++] = x; // ... }
以上杂乱的代码,使用std::vector是个更好的选择:
1 2 3 4 5 6 7
vector<int> v; v.reserve(100); // ... for (int x; cin >> x; ) { // ... check that x is valid ... v.push_back(x); }
参数的正确命名
为了更好的可读性,变量、函数参数的名称等都需要一个清晰的命名,必要时候需要为其自定义类型。
1 2 3
change_speed(double s); // bad: what does s signify? // ... change_speed(2.3);
上面这个代码,并没有明确标出 s 所对应的单位。
1 2 3 4
change_speed(Speed s); // better: the meaning of s is specified // ... change_speed(2.3); // error: no unit change_speed(23_m / 10s); // meters per second
这里定义了新的类型,便可以带有单位。
编译时检查优于运行时检查
在编译时检查既能很好的表达意图,还能提高代码的运行性能。
比如,下面的代码想要检查int类型是否大于 32 位:
1 2 3 4 5
int bits = 0; for (int i = 1; i; i <<= 1) ++bits; if (bits < 32) std::cerr << "int too small\n";
// separately compiled, possibly dynamically loaded // NB: this assumes the calling code is ABI-compatible, using a // compatible C++ compiler and the same stdlib implementation externvoidf3(std::unique_ptr<int[]>, int n);
externvoidf4(vector<int>&); // separately compiled, possibly dynamically loaded externvoidf4(span<int>); // separately compiled, possibly dynamically loaded // NB: this assumes the calling code is ABI-compatible, using a // compatible C++ compiler and the same stdlib implementation
voidg3(int n){ vector<int> v(n); f4(v); // pass a reference, retain ownership f4(span<int>{v}); // pass a view, retain ownership }
尽早的捕获运行时错误
比如下面的代码,当 m > n 时,就会发生数组越界:
1 2 3 4 5 6 7 8 9 10 11 12
voidincrement1(int* p, int n){ for (int i = 0; i < n; ++i) ++p[i]; }
voiduse1(int m){ constint n = 10; int a[n] = {}; // ... increment1(a, m); // maybe typo, maybe m <= n is supposed // but assume that m == 20 // ... }
structX { char ch; int i; std::string s; char ch2;
X& operator=(const X& a) {
}
X(const X&) {
} X() = default; };
X waste(constchar* p){ if (!p) throw std::invalid_argument("nullptr"); int n = std::strlen(p); auto buf = newchar[n]; if (!buf) throw std::bad_alloc(); for (int i = 0; i < n; ++i) buf[i] = p[i]; // ... manipulate buffer ... X x; x.ch = 'a'; x.s = std::string("", n); // give x.s space for *p for (int i = 0; i < x.s.size(); ++i) x.s[i] = buf[i]; // copy buf into x.s delete[] buf; return x; }