I've been using Boost in a DLL project but didn't export any Boost dependencies ...yet. Just C-Types and things which derive from the DLL Source tree itself.
But now I'm struggling with a lockable data model... I cannot get it designed exception safe and do not direct export boost types to the DLL interface.
struct DLL_EXPORT DllTestData {
double test1;
double test2;
void lock();
void unlock();
DllTestDataLock getGuard();
boost::mutex;
}
And use it:
DllTestData ptr;
ptr->lock();
ptr->test1 = 1.0;
ptr->unlock();
One could at least design probably some sort of DllTestData::Pimpl and hide the mutex type from the Dll. But If I want to use it like this:
DllTestData ptr;
{
auto g = ptr->getGuard();
ptr->test1 = 1.0;
}
While writing this I'm beginning to think about a ILockable-Interface and hide the mutex type in a PImpl or some sort, so something like this:
struct ILockable {
void lock() = 0;
void unlock() = 0;
}
struct DLL_EXPORT DllTestData : public struct ILockable {
/// ...
private:
class PImpl;
Pimpl * impl;
}
struct Guard {
Guard( ILockable * ptr ) {
ptr->lock();
}
~Guard() {
ptr->unlock();
}
}
And use it like this:
DllTestData ptr = fromDll();
{
Guard g(ptr);
ptr->test1 = 1.0;
}
Would this be a valid approach (hide mutex type with a pimpl and work with an Lockable interface) or am I going in the wrong direction with this? Or what would work better in this scenario? Maybe move the entire boost::mutex PImpl to the Interface?
Yes, in my opinion, you are on the right track. But you struct is so "heavy" that you should export it as an interface with get and set method of the values instead of the values itself. If you use the factory pattern, one function for create an object and one to delete you can safely deriver from the interface inside your dll without even expose the nasty Pimpl * impl.
Looking again at it, you can avoid exposing the mutex at all. For example, if only both values should be set at once, expose a
inside the methode, you can set the mutex yourself. Or the more classic Win32 approach if you don't want a big get and set list: expose a struct without any method like:
and add a function or method to your export like
inside your library you can lock and memcpy the whole struct. As said before, I am used to the second way during heavy use of the Win32 API, but I personal prefer the first approach with the interface and get/setter even if it takes more effort.