Jump to page: 1 2
Thread overview
using scoped_handle
Nov 23, 2006
Adi Shavit
Nov 23, 2006
Matthew
Nov 23, 2006
Adi Shavit
Dec 27, 2006
Matthew
Dec 27, 2006
Adi Shavit
scoped_handle and handle copies
Jan 31, 2007
Adi Shavit
Feb 01, 2007
Matthew Wilson
Feb 01, 2007
Adi Shavit
Feb 01, 2007
Matthew Wilson
Feb 01, 2007
Adi Shavit
Feb 01, 2007
Matthew Wilson
Feb 02, 2007
Matthew Wilson
Feb 02, 2007
Adi Shavit
Feb 02, 2007
Matthew Wilson
November 23, 2006
Hi,

  I have a 3rd party lib that provides various create/release functions
for various types.
They all return a pointer to the type (some are opaque some are not)
e.g. Type*.
I want to use scoped_handle with these to give me automatic release when
I go out of scope.
The problem is that the all the release functions accept as a parameter
Type**. This is, purportedly, done to that the release function can zero
the pointer.
This means that I cannot use scoped_handle as RAII, but only as a
separate object defined after the bare pointer (in the same scope).
If I define a forwarding function that accepts Type*& and forwards to
the original function (as &arg) , the code does not compile.

Any suggestions?

Thanks,
Adi


November 23, 2006
> I have a 3rd party lib that provides various create/release functions for various types. They all return a pointer to the type (some are opaque some are not) e.g. Type*.
>
> I want to use scoped_handle with these to give me automatic release when I go out of scope.

A jolly good idea. ;-)

> The problem is that the all
> the release functions accept as a parameter Type**. This is,
> purportedly, done to that the release function can zero the
> pointer. This means that I cannot use scoped_handle as RAII,
> but only as a separate object defined after the bare pointer
> (in the same scope). If I define a forwarding function that
> accepts Type*& and forwards to the original function
> (as &arg) , the code does not compile.
>
> Any suggestions?

None off the top of my head.

I'm done with my post-book break tomorrow, after which I'll apply my mind to this issue. Give me until after the w/e, and I'll see what I can conjure. <g>



November 23, 2006
Don't know how parse text/html message
December 27, 2006
> > Any suggestions?

> Well, I guess a wrapper that somehow (how?) binds the pointer to the first
> argument and accepts a dummy argument of type Type* that is not used.
> But this is not really elegant.
>
> Adi


Ok

I've managed to get an effective solution.

It's a prosaic, but functional, solution: just overload all the ctors for the by-ref functions. And the function translators now have another member type - indirect_function_type - and another method - translate_indirect().

I wanted to do it with an adaptor function template, something along the lines of

 template< typename R
              , typename H
              >
 function_creator<R, H, ???>::fn set_null_deref(R (*pfn)(H*) );

But as you can see from the ???, there's no way to get a function in there.
The answer would be to have the function_creator class hold some state, but
then that would require scoped_handle to understand function pointers and
some special kind of function object. It all seemed too much, so, even
though
it's an exponential solution - 6 more overloads to cover all calling
conventions and compiler weirdies - it's the way to go.

Not to mention that, despite the extra complexity to the library author,
it's
a great deal simpler to the user. They just continue to pass the function
to the s_h ctor, e.g.

  handle_t  handle_make(char const *);
  void         handle_close(handle_t);
  void         handle_close_set_null(handle_t *);

  { // old form
    handle_t                             h   =   handle_make("abc");

    scoped_handle<handle_t> sh(h, handle_close);
  }

  { // new form
    handle_t                             h   =   handle_make("def");

    scoped_handle<handle_t> sh(h, handle_close_set_null);
  }

using the adaptor would have required something like:

  { // new form with adaptor
    handle_t                             h   =   handle_make("def");

    scoped_handle<handle_t> sh(h, set_null_deref(handle_close_set_null));
  }

So the extra brain/finger strain's just for the librarian. In any case, I
think we're pretty safe from having a request to to R (*)(H***), don't you
agree? ;-)

I've a whole heap of testing to do now, to make sure this doesn't wreck anything, as it's a pretty fundamental component. But if it's good it'll be out with beta 35. (When, oh when will 1.9.1 proper ever get out there ... ? <g>)

Cheers

Matthew



December 27, 2006
Hi Matthew,

> Ok
>
> I've managed to get an effective solution.
>
> It's a prosaic, but functional, solution: just overload all the ctors for
> the by-ref functions. And the function translators now have another member
> type - indirect_function_type - and another method - translate_indirect().
>   
Yes, I guess this /would/ be the simplest solution.
> <snip>
> So the extra brain/finger strain's just for the librarian. In any case, I
> think we're pretty safe from having a request to to R (*)(H***), don't you
> agree? ;-)
>   
Yes.
Thanks!
Adi
January 31, 2007
Hi,


 Another question/remark about scoped_handle<>.

The docs say <http://www.synesis.com.au/software/stlsoft/doc-1.9/classstlsoft_1_1scoped__handle.html#_details> it:

   Provides automated scope-based cleanup of arbitrary resource types
   without any memory allocation required to implement the generic
   support.

   The template is parameterised on the resource type (e.g. FILE*, int,
   void*) and instances are initialised from a resource handle and the
   address of a (single-parameter) cleanup function, as in:

   <snip...>

    FILE                             *file = ::fopen("file.ext", "r");
    ::stlsoft::*scoped_handle*<FILE*>  h2(file, ::fclose);

     

Also, the class provides support for indirect cleanup function like releaseAndSetNull() (Thanks!).

However, note the program below:

   #include <stlsoft/smartptr/scoped_handle.hpp>

   int* getNewInt()
   {
      return new int(1);
   }
   void releaseIntAndReset(int** n)
   {
      delete *n;
      *n = 0;
   }


   int main()
   {
     int* i =0;
     //stlsoft::scoped_handle<int*> fgdet(i, releaseIntAndReset); //
   this will NOT release i
     i = getNewInt();
     stlsoft::scoped_handle<int*> fgdet(i, releaseIntAndReset);   //
   only this will release i
   }

My remarks might be just to clarify the documentation to specifically explain that (apparently) a COPY of the handle (e.g. i) is taken, and the release function is called on this copy, and NOT on the original (via a hypothetical reference).

I somehow assumed that a reference to the handle is kept so that in the program above, i will be properly released.

For example, with indirect releaseAndSetNull() functions, the setNull part is essentially thrown away, while the external pointer is left dangling.
If it is in the same scope then this is not a problem, but say i above is a member, which get tested for 0 and allocated and release repeatedly in different scopes (e.g. methods), then manual 0 assignment will be required and the whole point of the scoped_handle in this case is missed.

e.g.:

   int main()
   {
     int* i =0;
     {
        i = getNewInt();
        stlsoft::scoped_handle<int*> fgdet(i, releaseIntAndReset);   //
   release i, but not set i to 0
     }
     int j = (int)i; // j != 0;
   }


Of course, I can use the internal handle directly, but this is not always possible, and makes readability slightly harder.

Adi

February 01, 2007
>   Another question/remark about scoped_handle<>.
>
> The docs say
>
<http://www.synesis.com.au/software/stlsoft/doc-1.9/classstlsoft_1_1scoped__ handle.html#_details>
> it:
>
>     Provides automated scope-based cleanup of arbitrary resource types
>     without any memory allocation required to implement the generic
>     support.
>
>     The template is parameterised on the resource type (e.g. FILE*, int,
>     void*) and instances are initialised from a resource handle and the
>     address of a (single-parameter) cleanup function, as in:
>
>     <snip...>
>
>      FILE                             *file = ::fopen("file.ext", "r");
>      ::stlsoft::*scoped_handle*<FILE*>  h2(file, ::fclose);
>
>
>
> Also, the class provides support for indirect cleanup function like
> releaseAndSetNull() (Thanks!).
>
> However, note the program below:
>
>     #include <stlsoft/smartptr/scoped_handle.hpp>
>
>     int* getNewInt()
>     {
>        return new int(1);
>     }
>     void releaseIntAndReset(int** n)
>     {
>        delete *n;
>        *n = 0;
>     }
>
>
>     int main()
>     {
>       int* i =0;
>       //stlsoft::scoped_handle<int*> fgdet(i, releaseIntAndReset); //
>     this will NOT release i
>       i = getNewInt();
>       stlsoft::scoped_handle<int*> fgdet(i, releaseIntAndReset);   //
>     only this will release i
>     }
>
> My remarks might be just to clarify the documentation to specifically
> explain that (apparently) a COPY of the handle (e.g. i) is taken, and
> the release function is called on this copy, and NOT on the original
> (via a hypothetical reference).
>
> I somehow assumed that a reference to the handle is kept so that in the program above, i will be properly released.
>
> For example, with indirect releaseAndSetNull() functions, the setNull
> part is essentially thrown away, while the external pointer is left
> dangling.
> If it is in the same scope then this is not a problem, but say i above
> is a member, which get tested for 0 and allocated and release repeatedly
> in different scopes (e.g. methods), then manual 0 assignment will be
> required and the whole point of the scoped_handle in this case is missed.
>
> e.g.:
>
>     int main()
>     {
>       int* i =0;
>       {
>          i = getNewInt();
>          stlsoft::scoped_handle<int*> fgdet(i, releaseIntAndReset);   //
>     release i, but not set i to 0
>       }
>       int j = (int)i; // j != 0;
>     }
>
>
> Of course, I can use the internal handle directly, but this is not always possible, and makes readability slightly harder.


Seems like a hasty implementation on my part. I think the better solution is to ensure that the external resource handle is "null'd". I worked it out this morning (on my bike <g>), and have just to find a time to implement it. Basically, I'll add a union that holds a "H h" and a "H* ph". The scoped_handle will hold onto an instance of that, and a marker to say which is viable. The function translators will know which member to use anyway (translate() will use the h member; translate_indirect will use the ph member).

It's time for a beta 44 anyway. Just busy beavering with the last few issues on XSTLv1 - have so far chopped 600 pages to 545, and hope to get down to 500 - so it might be a day or two until I can do the STLSoft beta.

btw, this'll also be properly "rooted" - i.e. all will be below /stlsoft-1.9.1-beta44/ - as I've recently done to several other projects. I'm starting to toe the OS line ... ;-)

Once the book's sent off I will do STLSoft 1.9.1 proper. All that's really wanting is the docs and the website. So please keep sending in your documentation criticism.

Cheers

Matthew



February 01, 2007
Don't know how parse text/html message
February 01, 2007
You're right. I'd already considered this, and so decided that the "nulling" ctor overload would take an address of the handle. This has the big advantage that there can be no such confusion, and the small disadvantage that you can't "inline" the allocation function invocation with the scoped_handle ctor. ;-)

This should all work ticketyboo (LOL, don't you love the silly English and our daft expressions!). Just give me a few days to get over the last book push.

BigBoy

  "Adi Shavit" <adish@gentech.co.il> wrote in message news:epsgtf$hve$1@digitaldaemon.com...


Seems like a hasty implementation on my part. I think the better solution is
to ensure that the external resource handle is "null'd". I worked it out
this morning (on my bike <g>), and have just to find a time to implement it.
Basically, I'll add a union that holds a "H h" and a "H* ph". The
scoped_handle will hold onto an instance of that, and a marker to say which
is viable. The function translators will know which member to use anyway
(translate() will use the h member; translate_indirect will use the ph
member).
  Hmmm..
  That'll work and, indeed, fix the problem.

  However, I am concerned (from your point of view) that this would make 2 scoped_handle classes, with 2 subtly different behaviors.

  Ideally the union should (impossibly?) detect if the class was constructed with an externally held handle e.g.


  FILE                             *file = ::fopen("file.ext", "r");
  // ...
  {
     ::stlsoft::scoped_handle<FILE*>  h2(file, ::fclose);
     // ...
  }
  // ...
or used with the internally held handle e.g.

      ::stlsoft::scoped_handle<int> h1(::open("file.ext"), ::close);


  What would happen if I used an indirect function, with a reference to a temporary?
  Can this happen?
  Can the scope of the scoped_handle<> exceed the scope of the given temporary ?

  Something like this:

  // MyClass ctor
  MyClass():
      myScopedHandle(makeHandle(), ::releaseAndReset) // init myScopedHandle handle with indirect function
  {}

  Can this happen?
  makeHandle() will generate a temp handle, and myScopedHandle will hold a reference to it. When the ctor goes out of scope, what happens to the temp reference? (I'm not so clear about temp rules at the moment).
  In this case, it seems that a copy need to be made, not a reference.

  Confused,
  Adi







February 01, 2007
> You're right. I'd already considered this, and so decided that the "nulling" ctor overload would take an address of the handle. This has the big advantage that there can be no such confusion, and the small disadvantage that you can't "inline" the allocation function invocation with the scoped_handle ctor. ;-)
Actually, I'm not sure I understand what you mean.
The problem I mentioned was specifically related to and assumed taking a
reference.
Do you mean something like taking a reference as opposed to taking a
const reference to not compile (or select another ctor) when a temp is
given?
> This should all work ticketyboo (LOL, don't you love the silly English
> and our daft expressions!). Just give me a few days to get over the
> last book push.
> 
> BigBoy
You're in a good mood :-).
Adi


« First   ‹ Prev
1 2