在函数中隐藏内存分配是不好的做法吗?

Dav*_*ran 5 c malloc

我是否应该期望用户提供足够大小的内存块,比如将文件复制到缓冲区?或者我应该自己分配内存,并希望用户在完成后释放它?例如,函数strdup()本身分配内存,但该函数fread()只需要一个足够大小的缓冲区.

Mat*_*lia 5

这取决于 - 我已经看到C API使用所有类型的模式,例如:

  • 需要提供缓冲区和缓冲区大小的函数,并返回所需的大小(以便在被截断时调整缓冲区大小); NULL如果您只是询问缓冲区应该有多大,那么其中许多允许作为缓冲区传递; 这允许调用者使用现有缓冲区或分配适当大小的缓冲区,尽管有两个调用;
  • 单独的函数来获得所需的大小并填充缓冲区; 同上,但界面更清晰;
  • 需要缓冲区和缓冲区大小的函数,但如果NULL作为缓冲区传递则可以自己分配缓冲区; 最大的灵活性和简洁性,但功能签名可能会令人困惑;
  • 只返回新分配的字符串的函数; 简单易用,避免因无保护的截断而产生的错误,但如果性能受到关注则不灵活; 另外,要求调用者记住释放返回的值,如果使用堆栈分配的缓冲区,则在上述情况下可以避免;
  • 返回指向静态缓冲区的指针的函数,然后调用者负责对它做任何事情; 极易使用,极易误操作; 在多线程(需要线程本地存储)和重入是一个问题的情况下需要小心.

最后一个通常是一个坏主意 - 它带来了重入和线程安全的问题; 可以使用之前的那个但可能会造成效率问题 - 如果我已经有足够大的缓冲区,我通常不想浪费时间分配.所有其他人通常都很好.

但是除了接口的细节之外,如果你分配东西和/或返回指针,最重要的一点是清楚地记录谁拥有指向的内存 - 它是你库中的静态对象吗?它是指向调用者提供的对象内部的指针吗?它是动态分配的东西吗?调用者是否负责释放它?它只是作为参数提供的缓冲区吗?

最重要的是,如果你分配了东西,总是指定如何解除分配; 请注意,如果您正在构建一个可以编译为dll/so的库,那么提供自己的释放函数(即使它只是一个包装器free)是个好主意,以避免在运行的C运行时的不同版本之间出现不匹配同样的过程.此外,它避免将您的代码绑定到C库分配器 - 今天它可能没问题,明天可能会发现使用自定义分配器可能是一个更好的主意.

  • 这是关于libs的一个好点.如果开发人员没有意识到该库正在运行内存管理器/堆的不同实例,那可能会非常混乱:( (2认同)