The*_*rev 2 c memory-management
我已经组织了具有分配内存的功能的ac项目
例如,我得到了这个结构:
typedef struct t_example{
int x;
int y;
}example;
Run Code Online (Sandbox Code Playgroud)
我创建了这个函数来初始化一个实例:
/**
return value must be freed
*/
example * example_init(){
example *p_example = malloc(sizeof(example));
p_example->x = 42;
p_example->y = 42;
return p_example;
}
Run Code Online (Sandbox Code Playgroud)
我可以像这样调用这个函数
example *p_example = example_init();
Run Code Online (Sandbox Code Playgroud)
但随着我的项目的增长,我发现有时我不需要分配内存,如果我只需要堆栈上的局部变量,但需要初始化它,所以我将init函数更改为:
void example_init(example *p_example){
p_example->x = 42;
p_example->y = 42;
}
Run Code Online (Sandbox Code Playgroud)
所以我可以像这样调用这个函数
example o_example;
example_init(&o_example);
Run Code Online (Sandbox Code Playgroud)
当然,如果我有一个指针,这个功能也可以工作
example *p_example = malloc(sizeof(example));
example_init(p_example);
Run Code Online (Sandbox Code Playgroud)
我的问题是:这是最好的做法:1)提供,将分配内存(并正确记录本),因为它可以很方便进来的情况下的函数,或2),这应该是留给函数的调用者.
我还读到std函数没有动态分配内存,这就是strdup函数不是标准的原因.所以我会说第二种选择是最好的?
我的问题是:哪个是最佳实践:1)提供一个将分配内存的功能(并正确地记录这个),因为它可能在方便的情况下,或2)这应该留给函数的调用者.
我认为这不是最佳做法的问题.创建并返回(指向)新的动态分配对象的函数没有任何内在错误.为了比直接分配空间更有用,这样的函数应该确保为对象提供一致的初始值,尽管它可能通过调用不同的函数来实现.总的来说,这是C++ new运算符与构造函数相结合的C类比.
这并不排除用户自己分配对象,无论是动态还是其他方式.如果有问题的类型是公共的,那么可能有充分的理由提供不进行分配的初始化函数.正如您所看到的,这特别适用于依赖于自动或静态分配对象的代码.
我还读到std函数没有动态分配内存,这就是strdup函数不是标准的原因.所以我会说第二种选择是最好的?
标准委员会的标准库函数策略无法合理地扩展到您自己的功能.最终结果是任何地方都不能动态分配内存,如果这是委员会的意图,那么他们至少会弃用标准库的显式内存分配函数.
在处理非标量类型时,将分配、释放和初始化抽象到它们自己的函数中总是一个好主意。当您必须以特定顺序分配和取消分配多个资源时,它特别有用。
使用单独的函数进行分配和初始化:
example *example_create( void )
{
example *p = malloc( sizeof *p );
if ( !p )
log_error(); // or not - up to you
return p;
}
void example_init( example *p )
{
p->x = p->y = 42;
}
example *new_example = example_create( );
if ( new_example )
example_init( new_example );
Run Code Online (Sandbox Code Playgroud)
为了增加一些灵活性,您可以将初始化程序作为回调传递给分配器:
example *example_create( void (*example_initializer)(example *) )
{
example *p = malloc( sizeof *p );
if ( p )
if ( example_initializer )
example_initializer( p );
return p;
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以将分配和初始化合并为一个操作,但仍然保持分配和初始化相互解耦:
void init42( example *p ) { p->x = p->y = 42; }
void init0( example *p ) { p->x = p->y = 0; }
void initRand( example *p ) { p->x = rand(); p->y = rand(); }
example *p42 = example_create( init42 );
example *p0 = example_create( init0 );
example *pRand = example_create( initRand );
Run Code Online (Sandbox Code Playgroud)
而且,您仍然可以将初始化程序与auto变量一起使用:
example instance42;
init42( &instance42 );
example instance0;
init0 ( &instance0 );
example instanceRand;
initRand( &instanceRand );
Run Code Online (Sandbox Code Playgroud)