|
Boost : |
From: Maciej Sobczak (prog_at_[hidden])
Date: 2004-07-12 15:55:48
Hi,
Maxim Yegorushkin wrote:
>> I wrote a very simple class (see attachments), scoped_handle, which
>> encapsulates the resource (whatever it is) and its disposing (whatever
>> that means).
>> The techniques used are similar to those used in implementation of
>> boost::shared_ptr.
>> The example file shows how the class can be used to guard resources
>> allocated by operator new, fopen, open, etc.
> Well, the example has one major drawback - it uses new. The solution
> with shared_ptr has the same drawback. It looks overkill to use it for
> such a simple problem.
It depends on how you count this "simplicity".
For 99% cases I can think of (in fact, for 100% - the 1% margin is for
my humble assumption that one cannot think of everything ;) ), the smart
handle would be needed to provide exception safety to raw handles which
manage some external resources (files, sockets, DB connections,
sessions, statements, transactions, processes, etc.) and which automate
their cleanup. All these resources take much more time (usually orderS
of magnitude) to allocate and cleanup than a single new.
I've yet to see a realistic example where such resource is significantly
cheaper than operator new.
And even if this is realistic, it would be easy to extend the machinery
to use some tuned allocation strategy, like recycling memory pool, so
that the allocation by new comes down to just few CPU cycles.
In other words, I do not consider this solution to be an overkill.
Moreover, it is quite cheap and can buy some interesting features - for
example, you can change the deleter at run-time (the basic Strategy
pattern).
> I believe that scoped_handle must be as lightweight as possible.
Yes. But no lighter. ;)
> I've been using following simple implementation. Not a rocket science
> but it suited my needs quite well.
> template<class Handle>
> struct scoped_handle_traits
> {
> static Handle null() { return Handle(); }
> };
[...]
Interesting, but I would add is_null() predicate to the traits. This is
so that the Handle does not need to define its own operator== and
operator!= (but you can always delegate the generic traits to these
operators).
> template<
> class Handle
> , class Pfn
> , Pfn close
> , class Tag
> , class Traits = scoped_handle_traits<Handle>
> >
> class scoped_handle : private boost::noncopyable
[...]
> {
> public:
> typedef Tag tag_type;
[...]
Would you please explain what is the need for Tag or tag_type?
> Example of usage:
>
> typedef scoped_handle<HANDLE, BOOL(WINAPI*)(HANDLE), &::CloseHandle,
> class handle_tag> handle;
> typedef scoped_handle<HLOCAL, HLOCAL(WINAPI*)(HLOCAL), &::LocalFree,
> class hlocal_tag> hlocal;
-- Maciej Sobczak : http://www.msobczak.com/ Programming : http://www.msobczak.com/prog/
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk