views:

171

answers:

5

Is there a pattern that I may use for calling the required initialization and cleanup routines of an underlying (C) library? In my case, I would like to create the wrapper class so that it can be composed into other objects. The problem is that, when I destroy the wrapper class, the cleanup routines of the underlying library are called. That's fine until I instantiate multiple objects of my wrapper class. My question is what is the best way to really handle this situation? A static reference counter comes to mind, but I wanted to know if there were other potentially better options and the trades involved.

+2  A: 

Not everything has to be a class. The Singleton pattern would let you turn this into a class, but it's really not buying you anything over global functions:

bool my_library_init();
void my_library_shutdown();

The first call returns true if the library was successfully initialized, the second just quietly does whatever needs to be done and exits. You can add whatever reference counting or thread tracking type stuff behind these interfaces you like.

Also, don't neglect the possibility that your library may be able to do all of this transparently. When the first library function is called, could it detect that it is not initialized yet and set everything up before doing the work? For shutdown, just register the resources to be destroyed with a global object, so they are destroyed when the program exits. Doing it this way is certainly trickier, but may be worth the usability benefit to your library's callers.

Warren Young
If I understand you correctly, this would work if I could change the underlying library. In this case, I can't.
jdt141
Not at all. Write these two global functions yourself, then call them. It may be that your underlying C library provides such functions itself. Mainly, I'm arguing against knee-jerk "everything must be a class" thinking. I'm all for OOP where it makes sense, but I don't see the sense here.
Warren Young
The work that I'm doing is a library. I am a client to the shared resource in question. I want to abstract away the underlying library specific calls from my client. It would be bad practice to not completely initialize the object I'm creating in the ctor (partial initialization). What if the client forgets to call the initialization or shutdown calls? Then you'll (probably) get undefined behavior - not a good thing.
jdt141
If you have a ctor that requires that an underlying library be initialized, initialize the library in that ctor. Simple.
Warren Young
+1  A: 

If the initialization can be called before main starts, and cleanup called after main ends, this little trick (hack?) might work for you:

#include <iostream>

// C library initialization routine
void init() {std::cout << "init\n";}

// C library cleanup routine
void fini() {std::cout << "fini\n";}

// Put this in only one of your *.cpp files
namespace // anonymous
{
    struct Cleaner
    {
        Cleaner() {init();}
        ~Cleaner() {fini();}
    };
    Cleaner cleaner;
};

int main()
{
    std::cout << "using library\n";
}

Output:

init
using library
fini

It uses (abuses?) the fact that constructors for static objects are called before main, and that destructors are called after main. It's like RAII for the whole program.

Emile Cormier
also google for Static Initialization Order Fiasco. for example, the use of `std::cout` in `init` and `fini` has made this C++ rookie nervous: is it guaranteed to already/still exist?
just somebody
@somebody: It wasn't my intent to use a global object within another static object, but you raise an excellent point nonetheless.
Emile Cormier
Thanks, somebody. You made me disown this hackish answer. ;-P
Emile Cormier
A: 

If you can change the library implementation, you could have each call to one of the library's functions access a singleton which is created on first use.

Or you put a global/static variable into the library which initializes it during construction and shuts it down during destruction. (That might become annoying if the library uses global variables itself and the order of initialization/shutdown conflicts with them. Also, linkers might decide to eliminate unreferenced globals...)

Otherwise, I don't see how you want to avoid reference counting. (Note, however, that it has the drawback of possibly creating multiple init/shutdown cycles during the program's lifetime.)

sbi
A: 

If your set of C library routines is not too large, you can try combining the Singleton and Facade patterns so that C library routines are only invoked via the Facade. The Facade ensures the initialization and cleanup of the C library. Singleton insures that there is only one instance of the Facade.

#include <iostream>

// C library initialization and cleanup routines
void init() {std::cout << "init\n";}
void fini() {std::cout << "fini\n";}

// C library routines
void foo() {std::cout << "foo\n";}
void bar() {std::cout << "bar\n";}


class Facade // Singleton
{
public:
    void foo() {::foo();}
    void bar() {::bar();}
    static Facade& instance() {static Facade instance; return instance;}

private:
    Facade() {init();}
    ~Facade() {fini();}
};

// Shorthand for Facade::instance()
inline Facade& facade() {return Facade::instance();}


int main()
{
    facade().foo();
    facade().bar();
}

Output:

init
foo
bar
fini
Emile Cormier
maybe OT for the OP, but is this thread-safe?
just somebody
@somebody: Nope, `Facade::instance()` is not thread-safe. An easy (but ugly) workaround would be to call `Facade::instance()` in `main()` before any threads are spawned. At that point, it seems kinda silly to be using the facade, and you might as well be using `init`/`fini` directly in main.
Emile Cormier
I love how SO makes me learn about the subtleties of programming.
Emile Cormier
One *could* make Facade::instance synchronous using locks, but that would add a lot of unnecessary contention.
Emile Cormier
Thanks, somebody. You made me disown this hackish answer. ;-P
Emile Cormier
@somebody Thread safety is critically important here. thanks for catching this.
jdt141
A: 

I have seen a lot of Singleton talk, so I can only recommend a look at Alexandrescu's work.

However I am not sure that you really need a Singleton there. Because if you do, you assume that all your calls are going to share the state... is it the case ? Do you really wish when you call the library through a different instance of Wrapper to get the state in which the last call set it ?

If not, you need to serialize the access, and reinitialize the data each time.

class Wrapper
{
public:
  Wrapper() { lock(Mutex()); do_init_c_library(); }
  ~Wrapper() { do_clean_up_c_library(); unlock(Mutex()); }

private:
  static Mutex& Mutex() { static Mutex MMutex; return MMutex; }
}; // class Wrapper

Quite simple... though you need to make sure that Mutex is initialized correctly (once) and live until it's not needed any longer.

Boost offers facilities for the once issue, and since we use a stack based approach with MMutex it should not go awry... I think (hum).

Matthieu M.