Boost logo

Boost Users :

From: Edd Dawson (lists_at_[hidden])
Date: 2007-07-13 13:36:56


Hi Kirit!

Kirit Sælensminde wrote:
> Edd Dawson wrote:
>> Hi again, Kirit!
>>
>> Kirit Sælensminde wrote:
>>

>> template<typename T>
>> class ref_once_copied
>> {
>> public:
>> ref_once_copied(const T &obj) : obj_(new T(obj)), referenced_(false) { }
>> ~ref_once_copied() { if (referenced_) delete obj_; }
>> operator T &() { referenced_ = true; return *obj_; }
>>
>> private:
>> T *obj_;
>> bool referenced_;
>> };
>
> That looks like a pretty smart move. The first question I had was about
> using types so as to eliminate the bool. I.e. arrange for it to return a
> slightly different type, maybe via a function used to wrap this class.

I did spend a while thinking along those lines, but I failed to come up with
anything :(

> Now that I'm looking at it again though I'm not sure that I completely
> understand your implementation. It looks to me like you're always
> forcing a copy (in the constructor) so what job does referenced_ do?

I'm forcing a copy at the start. Copies of these objects are made a bunch of
times (~30, as I say) before they find their resting place inside some functor,
F say, created by boost::bind(). But copies of these ref_once_copied objects are
cheap, so they don't bother me.

Then, when F is called inside the child thread, the function proper is handed
these objects as arguments. At that point the conversion operators kick in. Once
that's happened, the referenced_ flag is set so that the destructor knows the
obj_ members have been used and can be deleted.

> I can see that it has value if you move the copy from the constructor into
> the type cast (the operator T &()), but as it is in the constructor if
> the reference isn't taken for some reason then it will leak a T.

That's true. But the conversion operator is *always* invoked exactly once, right
at the point where the actual function is called.

However, I had a nasty thought on the way to work today. By moving away from a
reference counted approach, I've lost exception safety. Essentially, I have code
that looks very roughly like this inside my async::call():

template< guff >
return_type_guff
call(const Caller &caller, const Functoid &f, const Argtype0 &a0, ..., const
ArgyTypeN &aN)
{
     return make_future(
         caller, boost::bind(&some_helper, f, wrap(a0), ..., wrap(aN))
     );
}

Each call to wrap() returns either its argument unmodified (if it's a
boost::reference_wrapper or a scalar) else an appropriate ref_once_copied<> made
from that argument.

But if one of those calls to wrap() throws, I'm going to be leaking left right
and center because the ref_once_copied<> destructors won't delete their obj_
members as the conversion operator wont have been called yet.

So for now I'm going to go back to reference counting. It's the only way I can
think of doing this safely.

> It looks like you've changed your mind about the semantics half way
> through implementing it.
>
>> I started out using a boost::shared_ptr<> for the obj_ member, but I realised
>> that approach outlined above would work just as well and also avoid the extra
>> overhead that the reference counting entails.
>
> I agree with this. In a multi-threaded environment those interlocked
> increments and decrements aren't cheap. A policy based implementation
> might be nice where we can provide the right threading semantics to the
> shared_ptr would be cool.

Well I'm leaning towards implementing my own very light-weight reference count
for use in ref_once_copied. In my implementation, I shouldn't need any
atomic/interlocked stuff at the argument-binding stage as far as I can tell.
However, I have to confess I'm still really rather new to multithreading and
concurrency which is why I felt the need to create an easy to use mechanism such
as this. So I may well be wrong.

>> So I just wanted to say thanks! I wouldn't have gone down this road if it wasn't
>> for your suggestion. Perhaps you'll find a use for this in your implementation?
>
> I certainly will! :-)
>
> You're the same Edd that has a C++ JPEG library as well aren't you? I've
> bookmarked it and will have a play with that once I get a chance.

That's me! I'd be interested to hear how you get on with it! I'm toying with the
idea of creatng a similar library for pngs, but that won't be for some time, yet.

Edd


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net