【问题标题】:Objections to free_if_heap(void *ptr)?反对 free_if_heap(void *ptr)?
【发布时间】:2020-08-14 07:39:32
【问题描述】:

我经常想使用一个假设的free_if_heap(void *ptr) 函数,因为这可以让我返回 malloc'd、静态或堆栈对象而不用关心。例如

char *foo(int arg) {
    if (arg < 0) {
        return "arg is negative";
    }

    if (arg > 0) {
        size_t size = snprintf(NULL, 0, "%i is an invalid value", arg);
        char *ret = malloc(size + 1); // FIXME: handle failure
        sprintf(ret, "%i is an invalid value", arg);
        // I use a varargs macro for the three lines above, to avoid format string duplication errors.
    }

    return NULL;
}

void main(void) {
    for (int i = -1; i < 2; ++i) {
        char *err = foo(i);
        if (err) {
            printf("Error: %s\n", err);
            free_if_heap(err);
        }
    }
}

显然,这样的函数肯定不是一个好主意,因为它甚至从未达到 malloc 库的水平,更不用说 C 标准了。

为什么free_if_heap(void *ptr) 是个坏主意?


更新:

函数foo 只是一个函数示例,它可以返回指向malloc 数据或静态/全局数据的指针。这不是一个有目的的严肃功能。


更新:

需要知道指针(其他已知类型,如char *)是否指向堆与需要知道void * 指针指向的数据类型不同。

free_if_heap(void *ptr) 采用void * 参数以避免free_if_heap_char(char *ptr)free_if_heap_int(int *ptr) 和其他一百个变体。

【问题讨论】:

  • @Yunnosch 返回字符串的size 是使用snprint 计算的,不写字符,而只是使用它的返回值。所需的size 然后是malloc'd,并且使用具有相同格式字符串的sprintf 将错误写入其中。我在宏中执行此操作,因此我只需编写一次格式字符串,避免错误。
  • 哦,我明白了。你不是在展示一个实现,你是在展示你想如何使用它。除了给定的例子,请解释更多。
  • 老实说,我认为问题是由可能返回需要释放的指针或不需要释放的指针的函数引起的。在我看来,这是一个设计错误。原因见我上面提供的链接。
  • Why is free_if_heap(void *ptr) a bad idea? 因为不需要确定指针是否指向堆所需的开销。 C程序员可以自己做。 C 程序员会想自己做,这样就不会执行神奇的附加代码。这个问题不是基于意见吗?
  • @Yunnosch 那么这使它成为无法回答的问题之一“为什么 C 中没有某些东西”,不是吗?不是,因为它从未实施过。因为它不存在。

标签: c malloc


【解决方案1】:

函数 void free_if_heap(void *ptr) 无法移植*,但它可能在选定的目标上实现,具体取决于 malloc() 的本地实现。

如果您不能或不想处理已分配对象的生命周期,您应该使用带有垃圾收集器的不同编程语言。 C 有许多有效的替代方案,例如 Go。您也可以尝试为 C 使用保守的垃圾收集器,例如 Boehm–Demers–Weiser garbage collector

但是请注意,跟踪内存分配的对象并在使用后正确处理它们并不是那么困难,但需要一致的约定:例如,您的 foo 函数应始终返回分配的字符串或空指针:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *foo(int arg) {
    if (arg < 0) {
        return strdup("arg is negative");
    }

    if (arg > 0) {
        size_t size = snprintf(NULL, 0, "%i is an invalid value", arg);
        char *ret = malloc(size + 1);
        if (ret != NULL) {
            snprintf(ret, size + 1, "%i is an invalid value", arg);
            return ret;
        }
    }
    return NULL;
}

int main(void) {
    for (int i = -1; i < 2; ++i) {
        char *err = foo(i);
        if (err) {
            printf("Error: %s\n", err);
            free(err);
        }
    }
    return 0;
}

(*) 可移植的实现将是微不足道且无效的:void free_if_heap(void *ptr) {}

【讨论】:

    猜你喜欢
    • 2019-10-23
    • 2023-04-11
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 2012-07-26
    • 2018-08-29
    • 2017-05-16
    相关资源
    最近更新 更多