【问题标题】:Returning a struct via copy, which encapsulates a pointer通过拷贝返回一个结构体,它封装了一个指针
【发布时间】:2013-01-05 08:11:54
【问题描述】:
假设我有以下内容:
typedef struct a_struct_s
{
int* dynamic_pointer;
}
a_struct;
a_struct make_struct( int length )
{
a_struct s;
s.dynamic_pointer = calloc( sizeof( int ), length );
// [check here to see if s.dynamic_pointer was allocated]
return s;
}
既然make_struct()会返回一个struct s的副本,那么被它封装的指针会不会泄露内存而无法释放?此外,副本本身与动态分配 s 相比是否存在性能成本?
【问题讨论】:
标签:
c
memory-management
memory-leaks
heap-memory
【解决方案1】:
没有。即使你复制了指针,它仍然指向同一个地方,所以你可以释放它。
【解决方案2】:
不,只要函数的调用者在结构指针成员上调用free(),它就不会泄漏内存。
记住规则:
当您调用 malloc,calloc 并且从不在同一个地址上调用 free 时,会发生内存泄漏。只要你这样做,就没有内存泄漏。
请注意,在从函数返回动态分配的指针时,指定所有权语义非常重要。简而言之,你的接口应该明确提到在函数调用之后动态分配的指针成员归调用者所有。
既然make_struct()会返回一个struct s的副本,那么被它封装的指针会不会泄露内存而无法释放?
是的,会返回结构的副本,但会返回 shallow copy。
基本上,这意味着返回的结构副本的指针成员指向的内存位置与s 的结构指针成员所指向的内存位置相同。
由于两个指针都指向同一个地址,只要调用者在返回结构的指针成员上调用free,就不会发生泄漏。
与动态分配s相比,副本本身是否存在性能成本?
动态分配总是成本高昂且更容易出错。尽量少用,除非你真的需要,否则不要使用。
【解决方案3】:
为什么会这样?指针本身不是分配的内存 - 如果您复制指针,它本身不会分配内存。如果您稍后在其上调用free(),它将被正确释放。即,此代码不会泄漏内存:
a_struct s = make_struct(10);
free(s.dynamic_pointer);
【解决方案4】:
不,从那个角度来看,这很好,但是您可能需要考虑使用另一种分配方法,因为按值返回结构并带有指向内存块的指针可能并不那么明显,以至于调用者需要释放其中的成员。
一种方法是使整个结构也被分配,然后有一个函数来释放结构
a_struct* alloc_struct( int length )
{
a_struct s = calloc( 1, sizeof(a_struct) );
s->dynamic_pointer = calloc( sizeof( int ), length );
return s;
}
void free_struct( a_struct *p )
{
if ( p != NULL )
{
free( p->dynamic_pointer );
free(p);
}
}