Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何隐式调用c风格的cleaner函数?_C++_C_Variables_Free_Destroy - Fatal编程技术网

C++ 如何隐式调用c风格的cleaner函数?

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

我正在处理一些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 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(...);