4

我有一个简单的结构:

typedef struct {
    int width, height;
    unsigned char *pixels;
} image;

哪个 API 更好?

image *imagecreate(int w, int h) {
    image *img = malloc(sizeof(image));
    img->width = w;
    img->height = h;
    img->pixels = calloc(w * h, 3);
    return img;
}

void imagefree(image *img) {
    free(img->pixels);
    free(img);
}

或者

image imagecreate(int w, int h) {
    image img;  
    img.width = w;
    img.height = h;
    img.pixels = calloc(w * h, 3);
    return img;
}

void imagefree(image *img) {
    free(img->pixels);
    img->width = img->height = 0;
}

?

为这样一个小结构做一个额外的 malloc() 似乎有点矫枉过正,它只是一个指向真正动态分配数据的指针的包装器。但另一方面,在值类型中隐藏指向动态分配内存的指针(对我而言)感觉不自然。人们可能会认为您不必释放它。

4

3 回答 3

2

你在谈论API。因此,让您的客户容易正确使用和难以错误使用是至关重要的。

选项 #2 的小改进

例如,如果我是您的第二个 API 的用户:

image imagecreate(int w, int h);
void imagefree(image *img);

我什至可能不会注意到需要调用imagefree,因为imagecreate返回一个对象,而不是指向对象的指针,而imagefree需要一个指针。我可能认为这imagefree只是delete image堆分配对象的包装。所以我不会将它用于“堆栈”对象。

因此,这更好:

image imagecreate(int w, int h);
void imagefree(image img);

虽然您在内部有一个堆分配的成员image,但您将其隐藏在这些 API 中,这很好。而且它们具有一致的“外观”,更好,更不容易出错。

那么选项#1呢?

至于您的第一个选择,那更好吗?这取决于(取决于个人)。至于我,我更喜欢选项#1。

image *imagecreate(int w, int h);
void imagefree(image *img);

为什么?

虽然我们没有办法通过 C++ 中的 RAII 之类的析构函数强制资源自动销毁,但通常会更加关注看到从 API 返回的“指针”的 C 程序员(我们对指针很敏感,不是吗? ? ;)。他们很可能一直在问自己:内部是动态分配的imagecreate吗?我需要通过其他 API 释放它吗?

于 2012-04-17T09:39:02.563 回答
1

不同之处在于您struct在第一种情况下是动态分配的,而在第二种情况下是自动分配的。这是个人喜好、编码标准和意见的问题。第二种方式对我来说似乎更安全,因为它少了一种free记住要做的事情,但既然你free无论如何都必须这样做 - 并不那么重要。

请注意,在第二种情况下,struct将复制到返回值中。您似乎很好地处理了其中的指针,但它在那里是潜在的地雷。

于 2012-04-17T08:17:01.500 回答
1

我会选择第一个。假设你的结构中有一个描述符'char name[100]',你的第二个将使用 100 字节的堆栈空间,它必须由操作系统处理,而第一个内存由你自己处理(使用自写的垃圾收集器而不是标准的malloc),您可以随意移动对象的句柄,而不必照顾有限的堆栈空间。

于 2012-04-17T09:07:07.470 回答