Boost logo

Boost :

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.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk