C++ 如何隐式调用c风格的cleaner函数?
我正在处理一些c API,我总是要检查一些变量是否已初始化,然后使用特殊函数清除/销毁/释放它们。例如分配:C++ 如何隐式调用c风格的cleaner函数?,c++,c,variables,free,destroy,C++,C,Variables,Free,Destroy,我正在处理一些c API,我总是要检查一些变量是否已初始化,然后使用特殊函数清除/销毁/释放它们。例如分配: ogg_stream_state os; ogg_stream_init(&os,ogg_page_serialno(&og)); 并摧毁: ogg_stream_clear(&os); 我想自动调用清洁器函数而不是显式的。< /p> < p>使用C++模板,你可以很容易地做:< /p> template<typename ARG, typename R
ogg_stream_state os;
ogg_stream_init(&os,ogg_page_serialno(&og));
并摧毁:
ogg_stream_clear(&os);
<>我想自动调用清洁器函数而不是显式的。< /p> < p>使用C++模板,你可以很容易地做:< /p>
template<typename ARG, typename RET>
class Destroyer
{
public:
typedef RET (*DestoyerFn)(ARG*);
Destroyer(DestoyerFn destroyer_fn, ARG* object_ptr) { objectPointer = object_ptr; destroyerFn = destroyer_fn;}
~Destroyer()
{
if(destroyerFn && objectPointer)
destroyerFn(objectPointer);
}
private:
DestoyerFn destroyerFn;
ARG* objectPointer;
};
现在,只要从函数返回,它就会调用cleaner函数。在实际场景中,您很可能希望在C函数周围使用某种自定义包装器,以封装它们,并避开类似C的行为和奇怪之处,例如调用约定 在现实世界中,我不相信您可以将任何C代码视为“通用C API”,并设计一些可以处理所有可能的C API的模板类。有太多的事情要考虑,使这样的泛型类可行。< /P> 例如,给定以下随机C代码:
//cfile.c
static int* something;
void cfunction_init (void)
{
printf("C function init\n");
something = (int*) malloc(sizeof(*something));
}
void cfunction_cleanup (void)
{
printf("C function cleanup\n");
free(something);
}
您可以创建如下的包装器类:
class wrapper
{
public:
wrapper() { cfunction_init(); }
~wrapper() { cfunction_cleanup(); }
};
OggStreamState os;
ogg_stream_init(os.state.get(),ogg_page_serialno(&og));
然后只需在适当的范围内声明一个包装类变量:
#include <iostream>
int main()
{
wrapper w;
std::cout << "C++ program executing" << std::endl;
return 0;
}
<>我会考虑使用自定义析构函数,用<<代码> SydRypPT/<代码>包装<代码> OGGJFielySturnEng/<代码>。p>
class OggStreamState {
public:
shared_ptr<ogg_stream_state> state;
OggStreamState() :
state(new ogg_stream_state, &ogg_stream_clear)
{}
};
这有点难看,但是这种技术为开始转向面向对象的接口而不是基于C函数的接口提供了一个合理的位置
例如,您可以将ogg\u stream\u init
移动到OggStreamState
中,使其成为
OggStreamState os;
os.init(ogg_page_seialno(&og));
再往前走一步,重复ogg_页面,你就会得到
OggPage og = ...;
OggStreamState os;
os.stream_init(og.serialno());
您甚至可以将init一直拉到构造函数中
OggStreamState os(og.serialno());
或者在极端
OggStreamState os(og);
与纯sentry RAII(如Lundin的解决方案)相比,它的另一个优点是,您可以轻松地将OggStreamState传入和传出函数。编译器将确定上次引用何时被销毁,并为您调用clear函数。i、 你可以安全地吃一顿饭
OggStreamState oss = function_that_returns_a_stream_state(...);
当然,这种技术确实会引入其他开销,但通常它们是最小的-而且它会稍微模糊ogg流的所有权,这可能是一件好事,也可能不是一件好事…名称是必需的。否则,构造函数将创建一个临时函数,析构函数将立即运行,而不是在作用域的末尾运行。您可以摆脱模板,使用
std::function
,并使用bind
获取函数。然后调用将看起来像销毁程序des_ogg_stream(std::bind(ogg_stream_clear,&os))代码>解决问题的不是模板,而是析构函数和RAII。但是模板可以很好地使用RAII。
OggStreamState os(og);
OggStreamState oss = function_that_returns_a_stream_state(...);