|
Boost : |
From: Douglas Gregor (gregod_at_[hidden])
Date: 2002-04-19 07:51:57
On Thursday 18 April 2002 11:56 pm, you wrote:
> >My general feeling is that there needs to be something like
>
> 'boost::smart_ptr<T>' which is appropriately configured for the
> specific
> needs of type 'T' (eg. intrusive vs. external counters are probably
> type specific), to application wide preferences (eg. multi-threading
> support is likely to be configured application wide - at least for
> most
> cases), and otherwise useful defaults.<
>
> The problem here is that you don't want to specialize smart_ptr<T> for
> all types that, for example, use COM's intrusive reference counting.
> There are many such types in the application and you don't really want
> to configure smart_ptr separately for each.
But suppose that you didn't need to configure smart_ptr individually for each
type. Would you then agree with the premise, that the type of reference
counting is almost always dependent on 'T' for 'smart_ptr<T>'?
If I have a type T with intrusive reference counting, I would expect
shared_ptr<T> to use that intrusive reference counting. If T is an open FILE,
I expect shared_ptr<T> to have an external reference count and know how to
fclose() the file when the count drops to zero. Having to specify the policy
along with the type _seems_ like it could be error-prone. If I'm supposed to
use 'smart_ptr<MyCOMObject, COMRefCountPolicy>' and I accidentally type
'smart_ptr<MyCOMObject>', bad things will happen.
But nobody wants to specialize a smart_ptr_traits for every single class.
However, reference counting is a property that is always inherited by derived
classes. We could massage the type traits notion a little so that we use
overloading instead of partial specialization: then base classes like
IUnknown can be taken into account so that anything derived from IUnknown
uses the COM reference counting mechanism.
We could have something like this:
template<typename T>
type_with_size<1> smart_ptr_traits_helper(void*, type<T>);
template<typename T>
type_with_size<2> smart_ptr_traits_helper(IUnknown*, type<T>);
type_with_size<3> smart_ptr_traits_helper(FILE*, type<FILE>);
Then the return value sizes perform the mapping over to a reference counting
policy:
template<>
struct smart_ptr_policy<1> { typedef external_ref_count_policy type; };
template<>
struct smart_ptr_policy<2> { typedef COM_policy type; };
template<>
struct smart_ptr_policy<3> { typedef FILE_policy type; };
So for smart_ptr<T>, the policy generator used is:
smart_ptr_policy<sizeof(smart_ptr_traits_helper((T*)0, type<T>()))>::type
smart_ptr_traits_helper has two parameters so that one can easily check for a
base class (via the base pointer conversion), an exact type (type<T>), or an
arbitrary predicate:
template<typename T>
type_with_size<N>
smart_ptr_traits_helpers(T*,
type<typename ct_if<my_trait<T>::value,
T,
do_not_unify>::type>);
I don't have a wonderful way to register new reference counting policies, but
I do have an ugly hack:
First, let BOOST_SMART_PTR_NEXT_POLICY_ID be a macro that will be
initialized to 1 by the smart_ptr header. Then we can add a new policy like
this:
template<typename T>
type_with_size<BOOST_SMART_PTR_NEXT_POLICY_ID>
smart_ptr_traits_helper(IUnknown*, type<T>);
#define BOOST_SMART_PTR_POLICY COM_policy
# include <boost/smart_ptr/register_policy.hpp>
#undef BOOST_SMART_PTR_POLICY
boost/smart_ptr/register_policy.hpp will add the appropriate specialization,
and then increment BOOST_SMART_PTR_NEXT_POLICY_ID:
template<>
struct smart_ptr_policy<BOOST_SMART_PTR_POLICY_ID>
{
typedef BOOST_SMART_PTR_POLICY type;
};
#if BOOST_SMART_PTR_POLICY == 1
# undef BOOST_SMART_PTR_POLICY
# define BOOST_SMART_PTR_POLICY 2
#elif BOOST_SMART_PTR_POLICY == 2
# undef BOOST_SMART_PTR_POLICY
# define BOOST_SMART_PTR_POLICY 3
#elif ...
I told you it was ugly :). Even so, it makes it possible to drop the explicit
reference counting policy parameter, and so long as your #includes are
consistent, smart_ptr<T> will always have the right policy.
> The threading policy is not application-wide; there are places when
> you want, and places when you don't want, to share smart pointers
> between threads.
Agreed.
Doug
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk