Re: Locking arbitrary resources without creating objects on the heap (longish)
Kai-Uwe Bux wrote:
Hendrik Schober wrote:
Hi,
suppose you have several different resources, all wrapped in
different classes, which all have 'lock()' and 'unlock()'
member functions. (A mutex would be a common example of such
a resource.) Of course, in order to be exception safe you
want to lock in some ctor and unlock in a dtor, so you need
to create lock classes for those resources. For the users,
the best would be to have the same lock class for all those
resources. Since they are different, non-related types, some
template-thingie will be required.
I have been thinking about this for a while and had a hard
time to come up with a solution. It's easy to setup something
that involves a dynamic object. Here's an outline of this:
class lock {
private:
struct locker_base {
virtual ~locker_base() {}
};
template< typename T >
struct locker : public locker_base {
locker(const T& obj) : obj_(obj) {}
~locker() {obj_.unlock();}
const T& obj_;
};
public:
template< typename T >
lock(const T& obj) : locker_(new locker<T>(obj) {}
~lock() {delete locker_;}
private:
locker_base* locker_;
};
The class 'lock::locker<T>' would store a reference to the
resource object and call the resource's 'unlock()' function
in its dtor.
This works, but has the disadvantage of creating an object
on the heap -- which might be OK for most resources, but
for some (de-)allocation/deallocation might dominate the
(un-)locking run-time.
What about:
class lock {
template < typename T >
static
void unlock_ptr ( void * t_ptr ) {
( reinterpret_cast< T* >( t_ptr ) )->unlock();
}
void * t_ptr;
void ( *unlock_fct ) ( void * );
public:
template < typename T >
lock ( T & t )
: t_ptr ( reinterpret_cast< void* >( &t ) )
, unlock_fct ( &unlock_ptr<T> )
{
t.lock();
}
~lock ( void ) {
unlock_fct( t_ptr );
}
}; // lock<>
I think the above implemention would be better without all the casts
and void pointers. So why not implement a typesafe, stack-based
resource locker that takes advantage the lock() and unlock() name
requirement of the lockable type? In other words, a solution along
these lines:
template <class T>
struct StLocker
{
public:
StLocker(T& t) : t_(&t)
{
t.lock();
}
~StLocker()
{
t_->unlock();
}
private:
T * t_;
};
Why would a resource locker class have to be any more complicated than
StLocker's implementation?
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]