www.digitalmars.com         C & C++   DMDScript  

c++.stlsoft - using scoped_handle

reply Adi Shavit <adish gentech.co.il> writes:
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

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
Nov 23 2006
next sibling parent reply "Matthew" <matthew hat.stlsoft.dot.org> writes:
 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>
Nov 23 2006
parent reply Adi Shavit <adish gentech.co.il> writes:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000066">
<small>Hi,</small>
<blockquote cite="midek3riu$ure$2 digitaldaemon.com" type="cite">
  <blockquote type="cite">
    <pre wrap="">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*&amp; and forwards to the original function
(as &amp;arg) , the code does not compile.

Any suggestions?
    </pre>
  </blockquote>
  <pre wrap=""><!---->
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.
&lt;g&gt;

  </pre>
</blockquote>
<small>Well, I guess a wrapper that somehow (how?) binds the pointer to
the first argument and accepts a dummy argument of type
<big><tt>Type*</tt></big>
that is not used. But this is not really elegant.<br>
<br>
Adi<br>
</small>
</body>
</html>
Nov 23 2006
parent reply "Matthew" <matthew hat.stlsoft.dot.org> writes:
 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
Dec 26 2006
parent Adi Shavit <adish gentech.co.il> writes:
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().
   

 <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? ;-)
   

Thanks! Adi
Dec 27 2006
prev sibling parent reply Adi Shavit <adish gentech.co.il> writes:
Hi,


  Another question/remark about scoped_handle<>.

The docs say 
<http://www.synesis.com.au/software/stlsoft/doc-1.9/classstlsoft_1_1scoped__h
ndle.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
Jan 31 2007
parent reply "Matthew Wilson" <matthew hat.stlsoft.dot.org> writes:
   Another question/remark about scoped_handle<>.

 The docs say

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
Jan 31 2007
parent reply Adi Shavit <adish gentech.co.il> writes:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body dir="ltr" bgcolor="#ffffff" text="#000066">
<br>
<blockquote cite="mideprcar$2bo4$1 digitaldaemon.com" type="cite">
  <pre wrap="">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 &lt;g&gt;), 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).
  </pre>
</blockquote>
Hmmm..<br>
That'll work and, indeed, fix the problem.<br>
<br>
However, I am concerned (from your point of view) that this would make
2 scoped_handle classes, with 2 subtly different behaviors.<br>
<br>
Ideally the union should (impossibly?) detect if the class was
constructed with an externally held handle e.g. <br>
<br>
<pre>  FILE                             *file = ::fopen("file.ext", "r");
  // ...
  {
     ::stlsoft::<b>scoped_handle</b>&lt;FILE*&gt;  h2(file, ::fclose);
     // ...
  }
  // ...
</pre>
or used with the internally held handle e.g. <br>
<br>
&nbsp;&nbsp;&nbsp; <tt>::stlsoft::<b>scoped_handle</b>&lt;int&gt;
h1(::open("file.ext"), ::close);<br>
<br>
</tt><br>
What would happen if I used an indirect function, with a reference to a
temporary?<br>
Can this happen? <br>
Can the scope of the <tt><b>scoped_handle&lt;&gt; </b></tt>exceed the
scope of the given temporary ?<br>
<br>
Something like this:<br>
<br>
<tt>// </tt><tt>MyClass </tt><tt>ctor<br>
MyClass(): <br>
&nbsp;&nbsp;&nbsp; myScopedHandle(makeHandle(), ::releaseAndReset) // init
</tt><tt>myScopedHandle
handle with indirect function<br>
{}<br>
</tt><tt><br>
</tt>Can this happen?<br>
<tt>makeHandle() </tt>will generate a temp handle, and <tt>myScopedHandle
</tt>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).<br>
In this case, it seems that a copy need to be made, not a reference.<br>
<br>
Confused,<br>
Adi<br>
<br>
<br>
<br>
<br>
<br>
</body>
</html>
Feb 01 2007
parent reply "Matthew Wilson" <matthew hat.stlsoft.dot.org> writes:
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

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.=20


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

      ::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?=20
  Can the scope of the scoped_handle<> exceed the scope of the given =
temporary ?

  Something like this:

  // MyClass ctor
  MyClass():=20
      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
Feb 01 2007
parent reply Adi Shavit <adish gentech.co.il> writes:
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit


 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. ;-)

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

Adi
Feb 01 2007
parent reply "Matthew Wilson" <matthew hat.stlsoft.dot.org> writes:
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

He he. I'm failing to communicate by trying to be terse. (Time is tres =
short this week.)

Basically, under my projected change, if you use a non-nulling release =
fn, you can call like this:

  scoped_handle<void*>  sh(::malloc(10), ::free);

or this:

  void *pv =3D ::malloc(10);

  scoped_handle<void*>  sh(pv, ::free);

If you're using a nulling release func, then you must call it like this:

  void free_set_null(void **);

  void *pv =3D ::malloc(10);

  scoped_handle<void*>  sh(&pv, free_set_null);

Note that you will pass &pv, not pv, in the second case. In other words, =
you pass a pointer to your variable. That way, all issues of =
const/non-const / temp/non-temp just disappears. The "cost" is just that =
we will remove the (recently added) ability to write:

  scoped_handle<void*>  sh(::malloc(10), free_set_null);

I'm of the opinion that that cost is worth paying. Thoughts?


As for my mood, well, I'm nearing the point where the final draft of =
XSTLv1 will be dispatched to the publishers - just tidying up, and =
waiting for cover quotes from reviewers ... - my boys (Bob luv 'em) are =
both back at school - so I can concentrate a bit better - and I have had =
very fruitful discussions with my editor about getting XSTLv2 trimmed =
down and therefore likely to be written in half the time I expected.

:-)

  "Adi Shavit" <adish gentech.co.il> wrote in message =
news:45C24A13.9010603 gentech.co.il...


    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
Feb 01 2007
next sibling parent "Matthew Wilson" <matthew hat.stlsoft.dot.org> writes:
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

I've implemented this now, and it works fine. I'll include this in the =
next beta.

  "Matthew Wilson" <matthew hat.stlsoft.dot.org> wrote in message =
news:eptn32$22tc$1 digitaldaemon.com...
  He he. I'm failing to communicate by trying to be terse. (Time is tres =
short this week.)

  Basically, under my projected change, if you use a non-nulling release =
fn, you can call like this:

    scoped_handle<void*>  sh(::malloc(10), ::free);

  or this:

    void *pv =3D ::malloc(10);

    scoped_handle<void*>  sh(pv, ::free);

  If you're using a nulling release func, then you must call it like =
this:

    void free_set_null(void **);

    void *pv =3D ::malloc(10);

    scoped_handle<void*>  sh(&pv, free_set_null);

  Note that you will pass &pv, not pv, in the second case. In other =
words, you pass a pointer to your variable. That way, all issues of =
const/non-const / temp/non-temp just disappears. The "cost" is just that =
we will remove the (recently added) ability to write:

    scoped_handle<void*>  sh(::malloc(10), free_set_null);

  I'm of the opinion that that cost is worth paying. Thoughts?


  As for my mood, well, I'm nearing the point where the final draft of =
XSTLv1 will be dispatched to the publishers - just tidying up, and =
waiting for cover quotes from reviewers ... - my boys (Bob luv 'em) are =
both back at school - so I can concentrate a bit better - and I have had =
very fruitful discussions with my editor about getting XSTLv2 trimmed =
down and therefore likely to be written in half the time I expected.

  :-)

    "Adi Shavit" <adish gentech.co.il> wrote in message =
news:45C24A13.9010603 gentech.co.il...


      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
Feb 01 2007
prev sibling parent reply Adi Shavit <adish gentech.co.il> writes:
Got it!
Makes perfect sense.
Thanks.
Sounds good.
Adi

Matthew Wilson wrote:
 He he. I'm failing to communicate by trying to be terse. (Time is tres 
 short this week.)
  
 Basically, under my projected change, if you use a non-nulling release 
 fn, you can call like this:
  
   scoped_handle<void*>  sh(::malloc(10), ::free);
  
 or this:
  
   void *pv = ::malloc(10);
  
   scoped_handle<void*>  sh(pv, ::free);
  
 If you're using a nulling release func, then you must call it like this:
  
   void free_set_null(void **);
  
   void *pv = ::malloc(10);
  
   scoped_handle<void*>  sh(&pv, free_set_null);
  
 Note that you will pass &pv, not pv, in the second case. In other 
 words, you pass a pointer to your variable. That way, all issues of 
 const/non-const / temp/non-temp just disappears. The "cost" is just 
 that we will remove the (recently added) ability to write:
  
   scoped_handle<void*>  sh(::malloc(10), free_set_null);
  
 I'm of the opinion that that cost is worth paying. Thoughts?
  
  
 As for my mood, well, I'm nearing the point where the final draft of 
 XSTLv1 will be dispatched to the publishers - just tidying up, and 
 waiting for cover quotes from reviewers ... - my boys (Bob luv 'em) 
 are both back at school - so I can concentrate a bit better - and I 
 have had very fruitful discussions with my editor about getting XSTLv2 
 trimmed down and therefore likely to be written in half the time I 
 expected.
  
 :-)
  

     "Adi Shavit" <adish gentech.co.il <mailto:adish gentech.co.il>>
     wrote in message news:45C24A13.9010603 gentech.co.il...

     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. ;-)

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

Adi

Feb 02 2007
parent "Matthew Wilson" <matthew hat.stlsoft.dot.org> writes:
"Adi Shavit" <adish gentech.co.il> wrote in message
news:epv15g$1175$1 digitaldaemon.com...
 Got it!
 Makes perfect sense.
 Thanks.
 Sounds good.
 Adi

Still going to be a while before I can do STLSoft release, so am including new scoped_handle here. No guarantees on its quality. Matty
Feb 02 2007