C 对象创建:指向值类型对象内动态分配的数据的指针-好还是坏?
我有一个简单的结构:C 对象创建:指向值类型对象内动态分配的数据的指针-好还是坏?,c,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
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);
}
或
?
对于这样一个小的结构,它只是一个指向实际动态分配数据的指针的包装器,对它执行额外的malloc()似乎有些过分。但另一方面,(对我来说)将指向动态分配内存的指针隐藏在值类型中感觉很不自然。有人可能认为您不必释放它。不同之处在于,您的
结构在第一种情况下是动态分配的,在第二种情况下是自动分配的。这是个人偏好、编码标准和观点的问题。第二种方法对我来说似乎更安全,因为它少了一种免费
记得要做的事,但既然你必须免费
,那就没那么重要了
注意,在第二种情况下,struct
被复制到返回值中。你似乎很好地处理了其中的指针,但这是一个潜在的地雷。我同意第一个。假设您的结构中有一个描述符“char name[100]”,那么第二个将使用100字节的堆栈空间,这必须由操作系统处理,而第一个内存将由您自己处理(使用自写垃圾收集器而不是标准的malloc)您可以随意移动对象的句柄,而无需考虑有限的堆栈空间。您正在谈论的是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
为什么?
虽然我们没有办法在C++中用RAII这样的析构函数来实现资源自动销毁,但是通常看到C程序员看到的是从API返回的指针(我们对指针敏感,不是吗?)。他们很可能一直在问自己:它是在imagecreate
中动态分配的吗?我需要通过其他API释放它吗?我当然更喜欢第一个,我认为指针更容易管理。我通常将字符串作为char*进行管理。但你是对的,如果我的结构在未来增长,我会浪费更多的堆栈空间。你说服了我。我可能会使用指针返回值版本。
image imagecreate(int w, int h);
void imagefree(image img);
image *imagecreate(int w, int h);
void imagefree(image *img);