CppCoreGuidelines P.9 不要浪费计算时间和计算空间
P.9: Don’t waste time or space
理由
This is C++.
注意
为更好达到既定目的,可以消耗更多计算时间和计算空间。比如加快开发进度、保障资源安全、简化系统测试。
亚历山大·斯特潘诺夫曾说过:追求效率的另一个好处是,这个过程可以迫使你更深入地理解所要解决的问题。
“Another benefit of striving for efficiency is that the process forces you to understand the problem in more depth.” - Alex Stepanov
注:亚历山大·斯特潘诺夫(Alexander Stepanov),Alex Stepanov, STL(标准模板库)之父,并因此在 1995 年获得了第一届Dr. Dobb’s程序设计杰出奖,他曾任 Compaq 公司副总裁和首席科学家,AT&T 实验室副总裁和首席构架师, SGI 服务器和巨型计算机公司技术总监。Alexander 曾先后在 HP 实验室、AT&T 实验室、通用电气公司 R&D、Polytechnic University of New York 大学控制研究所和复杂自动化研究所工作和研究了 25 年。他的研究工作涉及程序设计、语言设计、存贮系统、路径计划算法、实时操作系统等。
例子
struct X { char ch; int i; string s; char ch2; X& operator=(const X& a) { ch = a.ch; i = a.i; s = a.s; ch2 = a.ch2; return *this; } X() {ch='\0'; i=0; s=""; ch2='\0';} X(const X& a) {ch = a.ch; i = a.i; s = a.s; ch2 = a.ch2;} }; X waste(const char* p) { if (!p) throw bad_exception{}; int n = strlen(p); auto buf = new char[n]; if (!buf) throw bad_alloc{}; for (int i = 0; i < n; ++i) buf[i] = p[i]; // ... manipulate buffer ... X x; x.ch = 'a'; x.s = string(n, '\0'); // give x.s space for *p for (gsl::index i = 0; i < x.s.size(); ++i) x.s[i] = buf[i]; // copy buf into x.s delete[] buf; return x; } void driver() { X x = waste("Typical argument"); cout << x.s << endl; } int main() { driver(); return 0; }
Typical argument
以上例子以夸张的手法,展现了计算资源如何被无情的浪费。 X
的内部数据布局至少浪费了 6 字节(每个 char
处浪费 3 字节)。 buf
多余的创建和删除操作。
void lower(zstring s) { for (int i = 0; i < strlen(s); ++i) s[i] = tolower(s[i]); }
以上代码中,i < strlen(s)
每次循环都会执行。因为只是改了字符串字符的大小写,并不改变字符串长度,因此没必要重复计算 s
的长度。因此可以这样改:
void lower(zstring s) { int len = strlen(s); for (int i = 0; i < len; ++i) s[i] = tolower(s[i]); }
注意
个别例子中,我们很容易发现浪费资源的情况,也很容易修复。但是,如果整个代码库中都分散着浪费资源的情况,我们就很难及时发现并修复了。所以,本条指南期望能够在使用C++前发现大部分浪费资源的情况。然后,通过检查算法和需求,发现更深层次的资源浪费的情况。不过,这些超出了本指南的范围。
强化
- 检查标记返回值未被使用的,某些用户自定义的,非默认的后缀操作,如
operator++
和operator--
函数。选择使用前缀形式。