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

时间:2012-04-17 08:12:28

标签: c

我有一个简单的结构:

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

3 个答案:

答案 0 :(得分: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解除分配?

答案 1 :(得分:1)

不同之处在于,struct在第一种情况下动态分配,在第二种情况下自动分配。这是个人偏好,编码标准和意见的问题。第二种方式对我来说似乎更安全,因为它不会记得做free,但是因为你必须free,所以这并不重要。

请注意,在第二种情况下,struct被复制到返回值中。你似乎正在处理它中的指针,但它在那里是一个潜在的地雷。

答案 2 :(得分:1)

我会选择第一个。假设你的struct中有一个描述符'char name [100]',你的第二个将使用100byte的stackspace,它必须由操作系统处理,而第一个内存由我自己处理(使用自写垃圾收集器而不是标准的malloc)你可以随意移动手柄到周围的物体,而不必照顾你的限制堆栈空间。