29 December 2021

C++ 核心指南目录

如果系统长期运行的,哪怕没有及时释放很小的资源,都有可能导致系统资源耗尽。因此,及时释放系统资源是一种负责任的编程态度。

void f(char* name)
{
    FILE* input = fopen(name, "r");
    // ...
    if (something) return;   // bad: if something == true, a file handle is leaked
    // ...
    fclose(input);
}

以上例程中,如果 something 为真,函数直接返回了,没有及时关闭 input 文件结构体,产生资源泄漏。

void f(char* name)
{
    ifstream input {name};
    // ...
    if (something) return;   // OK: no leak
    // ...
}

改用 ifstream 文件输入对象可以避免资源泄漏。当函数返回的时候,自动调用解构函数释放内存数据。

所谓的泄漏(leak)通俗的讲,就是出现任何没有及时释放的资源(anything that isn’t cleaned up)。细分下去,更重要的一类泄漏是:任何不能被释放的资源(anything that can no longer be cleaned up)。比如在堆中分配一个对象,然后运行过程中,对象的地址指针被覆盖掉了。于是,就再也没办法释放这个对象了。所以,对任何中途结束的程序,要么释放内存,要么把分配的对象返回给上层函数继续使用或者晚些时候释放。

建议:

  • 审查指针的使用。区分有主和无主指针。如以上例子用标准库资源句柄替换。或者用 GSL 中的 unique_ptrshared_ptr 标记指针所有权。
  • 审查暴露的 newdelete ,相对的是定义了释放规则的封装的 new

      shared_ptr<int> p(new int[10][](int* p) {delete []p;})
    
  • 审查返回裸指针(raw pointer)的资源分配函数。比如: fopen, malloc, strdup.