P.8: 勿泄漏任务资源
原因
随着时间的推移,即使是资源的缓慢增长也会耗尽这些资源的可用性,这对于长时间运行的程序特别重要,但也是负责任的编程行为的基本部分。
糟糕的例子
void f(char* name){ FILE* input = fopen(name, "r"); // ... if (something) return; // 糟糕:如果 something == true,文件句柄就泄漏了 // ... fclose(input);}
优先使用RAII:
void f(char* name){ ifstream input {name}; // ... if (something) return; // OK: 没有泄漏 // ...}
参考: 资源管理部分
注意
泄漏通俗地说就是“任何没有被清理的东西”,更重要的分类是“任何不能再被清理的东西”。例如,在堆上分配了一个对象,然而丢失了指向该块内存(分配)的指针。 不应将此规则应用在程序关闭期间需返回长生命周期对象的分配(译注:在程序退出期间的内存分配可以不需要遵守这些规则),例如,依赖于系统保证的清理可以简化代码,比如关闭文件和在进程关闭时释放内存。然而,依赖于隐式清理的抽象也同样简单,而且通常更安全。
注意
使用生命周期安全性剖面(profile) 来消除泄漏,当与RAII提供的资源安全相结合时,就没了"垃圾回收"的需求。当使用类型和边界剖面(profiles)时,你可以获得由工具保证的类型和资源安全。
实施
- 查看指针:将它们分为非所有者(默认)和所有者(owner),在可行的地方,用标准库资源句柄替换所有者(如上面的示例所示),或者使用GSL中的owner来标记所有者。
- 查看裸用的new和delete
- 查看已知返回原始指针的资源分配函数(如fopen, malloc 和 strdup)