5

在 C 中,函数可以返回指向该函数动态分配的内存的指针,并要求调用代码释放它。要求调用代码为第二个函数提供一个缓冲区也是很常见的,该函数然后设置该缓冲区的内容。例如:

struct mystruct {
   int a;
   char *b;
};


struct mystruct *get_a_struct(int a, char*b)
{
    struct mystruct *m = malloc(sizeof(struct mystruct));
    m->a = a;
    m->b = b;

    return m;
}

int init_a_struct(int a, char*b, struct mystruct *s)
{
    int success = 0;
    if (a < 10) {
        success = 1;
        s->a = a;
        s->b = b;
    }

    return success;
}

一种或另一种方法更可取吗?我可以考虑两者的参数:对于 get_a_struct 方法,调用代码被简化,因为它只需要free()返回的结构;对于 init_a_struct 方法,调用代码无法释放()动态分配的内存的可能性非常低,因为调用代码本身可能分配了它。

4

4 回答 4

4

It depends on the specific situation but in general supplying the allocated buffer seems to be preferable.

As mentioned by Jim, DLLs can cause problems if called function allocates memory. That would be the case if you decide to distribute the code as a Dll and get_a_struct is exported to/is visible by the users of the DLL. Then the users have to figure out, hopefully from documentation, if they should free the memory using free, delete or other OS specific function. Furthermore, even if they use the correct function to free the memory they might be using a different version of the C/C++ runtime. This can lead to bugs that are rather hard to find. Check this Raymond Chen post or search for "memory allocation dll boundaries". The typical solution is export from the DLL your own free function. So you will have the pair: get_a_struct/release_a_struct.

In the other hand, sometimes only the called function knows the amount of memory that needs to be allocated. In this case it makes more sense for the called function to do the allocation. If that is not possible, say because of the DLL boundary issue, a typical albeit ugly solution is to provide a mechanism to find this information. For example in Windows the GetCurrentDirectory function will return the required buffer size if you pass 0 and NULL as its parameters.

于 2013-07-23T16:49:10.740 回答
1

“首选传递指针”,除非出于某种逻辑原因绝对要求每个对象都是“从堆分配的新对象” - 例如,它将作为节点放入链表中,并且链接 -列表处理程序最终将通过调用 free 来销毁元素 - 或“从这里创建的所有东西都将在稍后进行的其他情况” free

请注意,malloc如果可能,“不调用”始终是首选解决方案。调用不仅malloc需要一些时间,还意味着在某个地方,您将不得不调用free分配的内存,并且每个分配的对象都会占用几个字节(通常为 12-40 字节)的“开销”——因此为小对象分配空间绝对是浪费。

于 2013-07-23T01:12:31.663 回答
1

我认为提供已经分配的结构作为参数更可取,因为在大多数情况下,您不需要在调用代码中调用 malloc/calloc,因此担心释放它。例子:

int init_struct(struct some_struct *ss, args...)
{
    // init ss
}

int main()
{
    struct some_struct foo;
    init_struct(&foo, some_args...);
    // free is not needed
} 
于 2013-07-23T01:01:24.710 回答
0

我同意其他答案,即struct首选传递分配的值,但在一种情况下,可能首选返回指针。

如果您需要在最后显式释放一些资源(关闭文件或套接字,或释放结构内部的一些内存,或加入线程,或其他需要 C++ 中的析构函数的东西),我认为它可能是最好在内部分配,然后返回指针。

我认为是这样,因为在 C 中,它意味着某种合同:如果您分配自己的struct,则不必做任何事情来销毁它,并且它会在函数结束时自动清除。另一方面,如果你收到一些动态分配的指针,你会觉得有必要在最后调用一些东西来销毁它,这个destroy_a_struct函数是你将需要的其他清理任务放在旁边的地方free

于 2015-05-19T22:28:46.253 回答