Boost logo

Boost :

From: Maciej Sobczak (prog_at_[hidden])
Date: 2004-07-07 15:18:09


Hi,

(not sure if it was discussed before)

I've found Boost smart pointers inflexible in the sense that they
operate only on pointers.
It would be a good idea to generalize their interface to handle just
about anything that requires special care when destroying.
HANDLE (on Windows), FILE*, file descriptors (on Unix), third-party API
handles, etc. come to mind.

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.

Is it possible to achieve the same results with the existing Boost
libraries?
If not, is there any interest in developing this kind of class?

-- 
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/

//
// Copyright (C) 2004 Maciej Sobczak
// http://www.msobczak.com/
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//

#ifndef SCOPED_HANDLER_H_INCLUDED
#define SCOPED_HANDLER_H_INCLUDED

template <typename Resource>
class disposer_base
{
public:
     virtual ~disposer_base() {}
     virtual void dispose(Resource) = 0;
};

template <typename Resource, typename Deleter>
class disposer_impl : public disposer_base<Resource>
{
public:
     disposer_impl(Deleter d) : d_(d) {}
     void dispose(Resource r) { d_(r); }
     
private:
     Deleter d_;
};

template <typename Resource>
void simpleDeleter(Resource r) { delete r; }

template <typename Resource>
void arrayDeleter(Resource r) { delete [] r; }

// requirements:
// Resource and Deleter are copy-constructible and do not throw while copying
// For Resource r and Deleter d, d(r) is a valid expression that doesn't throw
template <typename Resource>
class scoped_handle
{
public:
     scoped_handle(Resource r)
          : r_(r)
     {
          initDeleter(simpleDeleter<Resource>);
     }
     
     template <typename Deleter>
     scoped_handle(Resource r, Deleter d)
          : r_(r)
     {
          initDeleter(d);
     }
     
     ~scoped_handle() { disp_->dispose(r_); delete disp_; }
     
     Resource get() const { return r_; }
     
private:
     scoped_handle(const scoped_handle &);
     scoped_handle & operator=(const scoped_handle &);
     
     template <typename Deleter>
     void initDeleter(Deleter d)
     {
          try
          {
               disp_ = new disposer_impl<Resource, Deleter>(d);
          }
          catch (...)
          {
               d(r_);
               throw;
          }
     }
     
     disposer_base<Resource> *disp_;
     Resource r_;
};

#endif // SCOPED_HANDLER_H_INCLUDED


#include "scoped_handle.h"
#include <iostream>
#include <functional>

// this is for Unix only
#include <fcntl.h>
#include <unistd.h>

using namespace std;

class A
{
public:
     A() { cout << "A()\n"; }
     ~A() { cout << "~A()\n"; }
};

void specialDeleter(A *p)
{
     cout << "special deleter: ";
     delete p;
}

void anotherSpecialDeleter(A *p, int i)
{
     cout << "another special deleter (" << i << "): ";
     delete p;
}

int main()
{
     {
     scoped_handle<A*> h1(new A);
     scoped_handle<A*> h2(new A, specialDeleter);
     scoped_handle<A*> h3(new A, bind2nd(ptr_fun(anotherSpecialDeleter), 7));

     // resources are released in the reverse order
     }
     
     {
     scoped_handle<FILE*> h4(fopen("test.txt", "w"), fclose);
     // ...
     }
     {
     // this is for Unix only
     scoped_handle<int> h5(open("test.txt", O_RDONLY), close);
     // ...
     }
     // etc.
}


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