C API设计:当malloc返回NULL时该怎么办?

Ism*_*awi 20 c malloc api-design

假设我正在用C编写一个小库 - 比如一些数据结构.如果我无法分配内存,该怎么办?

这可能非常重要,例如我需要一些内存来初始化数据结构,或者我正在插入一个键值对并希望将它包装在一个小结构中.它也可能不太重要,例如类似于pretty_print构建内容的良好字符串表示的函数.然而,它通常比你的平均错误更严重 - 可能没有任何意义继续下去.malloc如果返回,大量的在线样本使用直接退出程序NULL.我猜很多真正的客户端代码也会这样做 - 只是弹出一些错误,或写入stderr并中止.(而且很多真正的代码可能根本不检查返回值malloc.)

有时回归是有意义的NULL,但并非总是如此.错误代码(或只是一些布尔success值),无论是返回值还是输出参数都可以正常工作,但似乎它们可能会混乱或损害API的可读性(那么,可能在C语言中有点期待?) .另一种选择是让调用者可以随后查询某种内部错误状态,例如使用get_error函数,但是你必须小心线程安全,并且可能很容易错过; 无论如何,人们往往会对检查错误松懈,如果它完全是一个单独的功能,他们可能不知道它,或者他们可能不会打扰(但我猜这是他们的问题).

(我有时看到malloc包裹在一个函数中,只是再次尝试,直到内存可用...

void *my_malloc(size_t size)
{
    void *result = NULL;
    while (result == NULL)
        result = malloc(size);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

但这似乎有点愚蠢,也许很危险.)

处理这个问题的正确方法是什么?

R..*_*R.. 14

如果分配以阻止前进的方式失败,则库代码唯一可接受的解决方案是退出已在部分完成的操作中进行的任何分配和其他更改,并将失败代码返回给调用者.只有调用应用程序才能知道正确的方法是什么.一些例子:

  1. 音乐播放器可能只是中止或返回初始/停止状态并再次等待用户输入.
  2. 字处理器可能需要将当前文档状态的紧急转储存储到恢复文件然后中止.
  3. 高端数据库服务器可能需要拒绝并退出整个事务并向客户端报告.

如果您遵循经常但后退的想法,即您的库应该只是在分配失败时中止调用者,那么您将有许多程序确定他们无法使用您的库因此,您的用户使用您的库的程序将当分配失败导致其有价值的数据被丢弃时,会非常生气.

编辑:反对我的答案的一些"中止"阵营的一个反对意见是,在具有过度使用的系统上,malloc当内核尝试为分配的虚拟内存实例化物理存储时,即使对该似乎成功的调用也可能失败.这忽略了这样一个事实:任何需要高可靠性的人都会禁用过度使用,以及(至少在32位系统上)分配失败更可能是由于虚拟地址空间耗尽而不是物理存储耗尽.