I have created a class which wraps pointers and behaves like a pointer would behave, minus a few cases. It is a lock wrapper class which simply locks before usage of the pointer and unlocks once the pointer usage is done.
It must behave exactly like a pointer EXCEPT in the following cases:
- It cannot be implicitly converted to the pointer type it is pointing to
- It does not handle any implicit memory allocation/deallocation (it provides a method to delete the pointer to the object)
- When compared to another wrapper object, it compares their pointers to see if they are the same
Here is what I have so far:
template <class PtrType, class LockType>
class ELockWrapper {
public:
class Proxy {
public:
Proxy(PtrType* p, LockType* lock) : ptr(p), mLock(lock) { mLock->Lock(); }
~Proxy() { mLock->Unlock(); }
PtrType* operator->() { return ptr; }
PtrType operator*() { return *ptr; }
private:
PtrType* ptr;
LockType* mLock;
};
ELockWrapper() : ptr(nullptr), lock(nullptr) {}
ELockWrapper(nullptr_t t) : ELockWrapper() {}
ELockWrapper(PtrType *p, LockType* l) : ptr(p), lock(l) {}
ELockWrapper(PtrType *p, LockType& l) : ptr(p), lock(&l) {}
ELockWrapper(const ELockWrapper& copy) = default;
ELockWrapper& operator=(const ELockWrapper& x) = default;
bool operator==(const ELockWrapper& cmp) { return cmp.ptr == ptr; }
bool operator!=(const ELockWrapper& cmp) { return !operator==(cmp); }
bool operator==(PtrType* t) { return ptr == t; }
bool operator!=(PtrType* t) { return ptr != t; }
bool operator==(bool b) { return (ptr && b) || (!ptr && !b); }
bool operator!=(bool b) { return !operator==(b); }
operator bool() const { return ptr; }
Proxy operator->() {
return Proxy(ptr, lock);
}
PtrType operator*() {
return *Proxy(ptr, lock);
}
void Delete() {
Proxy(ptr, lock);
delete ptr;
}
private:
PtrType* ptr;
LockType* lock;
};
Here is it in action with some test cases.
Any mistakes/suggestions would be much appreciated.
One quick thing I want to ask: if ANY of the methods on ELockWrapper can be called concurrently, should I wrap each overloaded boolean operator with a lock? I'm thinking perhaps the delete method will be called, which a thread was interrupted in one of the operators might be problematic. Just a confirmation if this is the right thing to do?
Delete()
method is probably wrong (can't tell as there is no specification). The current behavior is LOCK, UNLOCK,delete ptr
. \$\endgroup\$operator->
returns an object with a lock count of one (likely expected) but it does so by locking twice and unlocking once. You may want to implement move semantics. \$\endgroup\$PtrType
is misleading, as that type is not a pointer. The standard usesvalue_type
for the target of a pointer or reference. \$\endgroup\$Lock()
andUnlock()
are incompatible function names (due to the capital letter) with the standard C++ library classes. If you simply named themlock()
andunlock()
, you wouldn't require a wrapper struct just to do so. \$\endgroup\$