我有一个简单的结构:
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()似乎太过分了,它只是一个指向实际动态分配数据的指针的包装器。但另一方面,在值类型中隐藏指向动态分配内存的指针(对我来说)感觉不自然。有人可能认为你不必释放它。
答案 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)你可以随意移动手柄到周围的物体,而不必照顾你的限制堆栈空间。