boost::mem_fn with Alexandrescu LockingProxy

Hello, the list. After some digging through the bind and mem_fn documentation, I have been unable to figure out whether I'm attempting to do something impossible or not. I've created a thread-safe variant of shared_ptr that uses Alexandrescu's LockingProxy to ensure that access to the contained object through operator-> correctly locks and unlocks the pointee object. In all respects save one, this "shared_locking_ptr" is syntactically equivalent to boost::shared_ptr. The one thing it cannot do is dereference the pointer via operator* (I can't figure out how to return something from operator* that remains in scope (and thus locked) long enough for the operation to complete). All well and good so far. Where I'm trying to use this beast is in boost::signals via bind (and therefore mem_fn). I'd like to connect a member function of an object to the signal through my shared_locking_ptr, so that when the signal fires it automatically locks the object, invokes the member function, and then unlocks. Shared pointers to objects are valid arguments to mem_fn; my shared_locking_ptr isn't, alas, apparently because it requires the operator* mentioned above. So: 1) Has anybody else attempted to extend shared_ptr for Alexandrescu's policy-based storage types, specifically the LockingProxy, and figured out how to overload operator* in a meaningful way? or 2) Is there some way to wheedle signals, bind, and/or mem_fn so that they only access the slot through operator->, and don't try to dereference it? If this is more properly a boost developer's list question, let me know and I'll take it there. Thanks! -- Allison Floyd

operator -> is recursive. It is applied until the initial ptr type is retrieved. operator* is not. But as I think you can try to introduce the casting operator to the contained type: template<class T> struct LockingProxy { //ctors (might be with params) that lock //dtor that unlocks //T* operator-> //T& operator* operator T&()const; private: T t; }; I assume you have following type: shared_ptr< LockingProxy<T> > ptr(new LockingProxy(params for T's ctor)); Now you could at least call it: (static_cast<T&>(*ptr)).member_of_T; Or if you need to pass the T& to some other function without casts: void do_smth(T const& t); do_smth(*ptr); You can also provide a function which makes this for you: template<class T> T& get_inst(LockingProxy<T> const& r) { return *r; } do_smth(get_inst(*ptr)); Hope that helps, Best Regards, Ovanes -----Original Message----- From: Allison Floyd [mailto:allison.floyd@gmail.com] Sent: Thursday, January 25, 2007 6:44 PM To: boost-users@lists.boost.org Subject: [Boost-users] boost::mem_fn with Alexandrescu LockingProxy Hello, the list. After some digging through the bind and mem_fn documentation, I have been unable to figure out whether I'm attempting to do something impossible or not. I've created a thread-safe variant of shared_ptr that uses Alexandrescu's LockingProxy to ensure that access to the contained object through operator-> correctly locks and unlocks the pointee object. In all respects save one, this "shared_locking_ptr" is syntactically equivalent to boost::shared_ptr. The one thing it cannot do is dereference the pointer via operator* (I can't figure out how to return something from operator* that remains in scope (and thus locked) long enough for the operation to complete). All well and good so far. Where I'm trying to use this beast is in boost::signals via bind (and therefore mem_fn). I'd like to connect a member function of an object to the signal through my shared_locking_ptr, so that when the signal fires it automatically locks the object, invokes the member function, and then unlocks. Shared pointers to objects are valid arguments to mem_fn; my shared_locking_ptr isn't, alas, apparently because it requires the operator* mentioned above. So: 1) Has anybody else attempted to extend shared_ptr for Alexandrescu's policy-based storage types, specifically the LockingProxy, and figured out how to overload operator* in a meaningful way? or 2) Is there some way to wheedle signals, bind, and/or mem_fn so that they only access the slot through operator->, and don't try to dereference it? If this is more properly a boost developer's list question, let me know and I'll take it there. Thanks! -- Allison Floyd _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On 1/26/07, Ovanes Markarian <om_boost@keywallet.com> wrote:
template<class T> struct LockingProxy { operator T&()const;
private: T t; };
I hadn't tried the cast operator variant; the syntax works, but...
I assume you have following type:
shared_ptr< LockingProxy<T> > ptr(new LockingProxy(params for T's ctor));
what I've actually got is shared_locking_ptr<T> ptr(new T()) where shared_locking_ptr::operator->() returns LockingProxy<T>, and shared_locking_ptr::operator*() wants to return T&. With either the cast operator you described or the more obvious LockingProxy::operator*() that I'd tried first, the LockingProxy goes out of scope (and thus unlocks) as soon as its operator completes, and before the result actually gets used. It occurs to me that there's possibly a way to do this via shared_ptr<LockingProxy<T> >, where the "ownership" of T belongs to something other than the shared_ptr or the LockingProxy; I'd originally thought that the T object would be conventionally owned by the shared_ptr and merely locked/unlocked via the proxy on access. But perhaps I'm going at this the wrong way...
Now you could at least call it:
(static_cast<T&>(*ptr)).member_of_T;
Or if you need to pass the T& to some other function without casts:
void do_smth(T const& t);
do_smth(*ptr);
This is exactly what I was trying to accomplish, with T staying locked all the way through the do_smth() call. (gory details, in case it matters: I'd originally planned on modifying boost::shared_ptr to take a second template argument (the storage policy), and then the "shared_locking_ptr" would just be a shared_ptr with a locking storage policy. Turns out that was harder than it looked at first sight.) -- Allison

Allison Floyd wrote:
Hello, the list.
After some digging through the bind and mem_fn documentation, I have been unable to figure out whether I'm attempting to do something impossible or not. I've created a thread-safe variant of shared_ptr that uses Alexandrescu's LockingProxy to ensure that access to the contained object through operator-> correctly locks and unlocks the pointee object. In all respects save one, this "shared_locking_ptr" is syntactically equivalent to boost::shared_ptr. The one thing it cannot do is dereference the pointer via operator* (I can't figure out how to return something from operator* that remains in scope (and thus locked) long enough for the operation to complete). All well and good so far.
Where I'm trying to use this beast is in boost::signals via bind (and therefore mem_fn). I'd like to connect a member function of an object to the signal through my shared_locking_ptr, so that when the signal fires it automatically locks the object, invokes the member function, and then unlocks. Shared pointers to objects are valid arguments to mem_fn; my shared_locking_ptr isn't, alas, apparently because it requires the operator* mentioned above.
mem_fn uses get_pointer(sp) to obtain a "raw pointer" which is then used as a first argument to operator->*. If you return a locking proxy from your get_pointer overload and implement operator->* for your locking proxy, it should work as you want.
participants (3)
-
Allison Floyd
-
Ovanes Markarian
-
Peter Dimov