How to implicitly call c-style cleanup functions?

I am working on some c Apis and I always need to check that some variables are initialized and then clear / destroy / free them with special functions. such as highlighting:

ogg_stream_state os;
ogg_stream_init(&os,ogg_page_serialno(&og));

      

and destruction:

ogg_stream_clear(&os);

      

I want to call the cleanup function automatically and implicitly.

+3


source to share


3 answers


With C ++ Templates, you can do this easily:

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;
};

      

ARG

is the argument of your cleaner function, and RET

is the return type ( RET

to avoid a compiler warning.)



Call example:

Destroyer<ogg_stream_state, int> des_ogg_stream(ogg_stream_clear, &os);

      

now everyone where you like, just return from your function, it will call your cleanup function.

+2


source


In a real world scenario, you most likely want to create some kind of custom wrapper around C functions, encapsulate them, and evade C like behavior and oddities like calling convention.

In the real world, I don't think you can treat any C code as a "generic C API" and develop some template class that can handle every possible C API. There are too many things to consider making such a general class doable.

For example, given the following random C code:

//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);
}

      

You can create a wrapper class like this:



class wrapper
{ 
  public:
    wrapper()  { cfunction_init(); } 
    ~wrapper() { cfunction_cleanup(); }
}; 

      

Then just declare your wrapper class variable in the appropriate scope:

#include <iostream>

int main()
{
  wrapper w;

  std::cout << "C++ program executing" << std::endl;

  return 0;
}

      

Program output:

C function init
C++ program executing
C function cleanup

      

0


source


I would consider ogg_stream_state

using a wrapper with a shared_ptr

custom destructor.

class OggStreamState {
public:
  shared_ptr<ogg_stream_state> state;
  OggStreamState() : 
    state(new ogg_stream_state, &ogg_stream_clear)
    {}
};

      

Your code will now look like this:

OggStreamState os;
ogg_stream_init(os.state.get(),ogg_page_serialno(&og));

      

It's a little ugly, but this method provides a logical place to jump to an object-oriented interface rather than a function based function.

For example, you could move ogg_stream_init

to OggStreamState

so that it becomes

OggStreamState os;
os.init(ogg_page_seialno(&og));

      

Take it one more step and repeat for ogg_page and you get

OggPage og = ...;
OggStreamState os;
os.stream_init(og.serialno());

      

You can even run init completely in the constructor

OggStreamState os(og.serialno());

      

or as a last resort ...

OggStreamState os(og);

      

Another benefit of doing this in pure hourly RAII (like a solution from Lundin) is that you can pass OggStreamState from functions without issue. The compiler will figure out when your last reference is destroyed and call the clear function for you. that is, you can safely have

OggStreamState oss = function_that_returns_a_stream_state(...);

      

Of course this method introduces other overhead, but it's usually minimal - it also slightly blurs the ownership of the ogg stream, which is a lot or might not be very good ...

0


source







All Articles