$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: svanechel_at_[hidden]
Date: 2001-06-13 00:52:12
--- In boost_at_y..., "George A. Heintzelman" <georgeh_at_a...> wrote:
> > Hi,
> > 
> > Recently I grew tired always having to write the same boiler 
plate 
> > code when I wanted to manage a resource using the "resource 
> > acquisition is initialization" technique. 
> 
> [snip]
> > * the non-copyable resources (boost::scoped_ptr and 
> > boost::scoped_array)
> > * the shared resources (boost::shared_ptr and boost::shared_array)
> > * resources that aren't shared but can be copied (E.g. Win32
> > HANDLE 
> > values)
> > 
> > Three base classes handle these three cases.
> > 
> > I would very much appreciate some input on the issue (is this 
> > approach OK? Is the solution useful enough to be turned into a 
> > library?)
> 
> Hi,
> 
> I'd be interested in this approach, especially if it saves me some 
> syntax. Can you give an example of the use of these classes (say, 
show 
> us the implementation of scoped_ptr with it)? The problem I see is 
that 
> I don't see a whole lot of typing getting saved with the standard 
> full-ownership RAII classes. The other cases maybe.
OK, here goes. The scoped_ptr is implemented by first implementing 
the traits class:
template<typename T>
class object_resource_traits
{
public:
        //static const T* nul = 0;
        static T* nul;
        static destroy( T* ptr ){ boost::checked_delete( ptr ); }
        static reset( T*& dst, T* src ){ boost::checked_delete( 
dst ); dst = src; }
};
Next a class is derived from basic_resource like this:
template<typename T>
class scoped_ptr : public basic_resource<T*, 
object_resource_traits<T> >
{
        typedef	basic_resource<T*, object_resource_traits<T> > base;
public:
        typedef	T element_type;
        scoped_ptr( T* p = 0 ) :
                base( p ) {}
        T* operator->() const { return ( base::get() ); }
        T& operator*() const { return ( *base::get() ); }
        operator T*() const { return ( base::get() ); }
};
Derivation is only necessary because smart_ptr is templatized as 
well. You're right that for these case not a whole lot of typing is 
saved. Most other OS resources can be handled with a simple typedef 
(up next).
> Also, I'm not a Win32 programmer at all. Can you maybe explain in 
what 
> sense these things can be copied but aren't shared? If two things 
have 
> a copy, they are sharing the resource, no?
You can have handles to OS objects that can be duplicated. They both 
refer to the same object after duplication but can have different 
access rights. Or you can have handles to objects that are actually 
duplicated (like icons). Here's an example of how Win32 HANDLEs are 
wrapped:
lass win32_handle_traits
{
public:
 static HANDLE nul;
 static void destroy( HANDLE h ) { if ( NULL != h ) ::CloseHandle( 
h ); }
 static void reset( HANDLE& dst, HANDLE src ) { destroy( dst ); dst = 
src; }
 static HANDLE duplicate( HANDLE h )
 {
  HANDLE	temp;
  if ( FALSE == ::DuplicateHandle( ::GetCurrentProcess(), h,
                ::GetCurrentProcess(), &temp, 0, FALSE,
                DUPLICATE_SAME_ACCESS ) )
  {
    throw  std::runtime_error( "Cannot duplicate handle" );
  }
  return ( temp );
 }
};
HANDLE win32_handle_traits::nul = NULL;
typedef basic_unique_resource<HANDLE, win32_handle_traits> handle;
Hope this clarifies things for you.
Svenne.