$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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