Library semantics

Started by
3 comments, last by antareus 19 years, 3 months ago
Suppose we have a class:

// RAII wrapper around a DLL.
class DynamicLibrary
{
public:
template<typename T>
DynamicLibrary(const T* name) :
 _handle(LoadLibrary(name))
{
 if(_handle == 0)
  throw DynamicLibraryException();
}

~DynamicLibrary()
{
 FreeLibrary(_handle);
}

template<typename T>
T GetSymbol(const char* name)
{
 return reinterpret_cast<T>(GetProcAddress(_handle, name));
}

private:
HMODULE _handle;
};

Typically, the user either: a. loads the DLL in question temporarily, calls a function, gets rid of it b. loads a bunch of DLLs for quite awhile (plug-ins) and unloads them much later b. is probably more prevalent than a. The question is, how do I accomodate the second case gracefully? Because this is little more than a RAII wrapper, they can't just throw it inside a container. "Use reference counted pointers" you say. Well, maybe. Like I said in another post, it seems kind of silly to dynamically allocate memory just to get a little more control over the lifetime of the object. Technically, I could use a non-const copy constructor to hand off ownership until the last instance bites the dust, but I gathered this isn't entirely kosher (from my discussion on auto_ptrs earlier).
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
Advertisement
The only thing I can think of is to change the class to a DLL container.
This would give you a bunch of DLL's that are freed when the instance of the container is destroyed instead.
Not the best solution though...I would use smart ptrs...=)

class DynamicLibraryContainer{public:typedef DLLHandle int;DLLHandle LoadDLL(const char *name){  HMODULE handle = LoadLibrary(name);  if(handle == 0)    throw DynamicLibraryException();  if('_handles' does not contain 'handle')    _handles.push_back(handle);  return 'index to handle';}~DynamicLibraryContainer(){ FreeLibrary(_handles[0..n]);}template<typename T>T GetSymbol(DLLHandle, const char* name){ return reinterpret_cast<T>(GetProcAddress(_handles[DLLHandle], name));}private:vector<HMODULE> _handles;};
There really is no difference between your two cases: its all a question of scope. If you want to load a dll for a plugin then you just keep the DynamicLib class alive for the duration that the plugin is required for. IIRC there is no problem in obtaining multiple handles to the same DLL - windows will simply do the reference counting behind the scenes as it has to do reference counting of DLL's across the whole system anyway.

BTW why is your constructor templated? LoadLibrary takes const char array as its argument and so you should simply have a single constructor.

Its also a good idea to make the copy constructor private to disallow copy construction as that will break the RAII idiom.

James
Quote:If you want to load a dll for a plugin then you just keep the DynamicLib class alive for the duration that the plugin is required for

This is the problem. How do you keep a bunch of dynamically loaded DLLs in scope with antareus approach (without dynamic allocation of each instance)? If you push them in a container they will be copied. Of course, it's possible to push an empty instance first, and then call Load on it or something...

I guess this is a general thought about RAII, so the fact that windows handles ref counting in this case is irrelevant.
Thanks for the responses.

Quote:BTW why is your constructor templated? LoadLibrary takes const char array as its argument and so you should simply have a single constructor.

That should have been a TCHAR. My mistake.

As for the intrusive reference counting idea, I will go with that approach. Thanks!
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis

This topic is closed to new replies.

Advertisement