对象创建:指向值类型对象内动态分配数据的指针 – 好还是坏?

我有一个简单的结构:

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()似乎太过分了,它只是一个指向实际动态分配数据的指针的包装器.但另一方面,在值类型中隐藏指向动态分配内存的指针(对我来说)感觉不自然.有人可能认为你不必释放它.

最佳答案
你在谈论API.所以至关重要的是,您的客户应该很容易正确使用并且难以正确使用.

选项#2的小改进

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

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

我可能甚至不会注意到需要调用imagefree,因为imagecreate返回一个对象,而不是一个指向对象的指针,而imagefree需要一个指针.我可能认为imagefree只是堆分配对象的删除图像的包装.所以我不会将它用作“堆栈”对象.

因此,这更好:

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

虽然在映像中有一个堆分配的成员,但是你在这些API中隐藏它是好的.并且它们具有一致的“外观”,这种外观更好,并且不易出错.

选项#1怎么样?

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

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

为什么?

虽然我们没有办法通过像C中的RAII这样的析构函数来强制执行资源自动销毁,但通常会更多关注那些看到从API返回的“指针”的C程序员(我们对指针敏感,不是我们?;).他们很可能会不断问自己:它是否在imagecreate中动态分配?我是否需要通过其他API解除分配?

转载注明原文:对象创建:指向值类型对象内动态分配数据的指针 – 好还是坏? - 代码日志