开发者

handle management with boost::shared_ptr<>

开发者 https://www.devze.com 2023-01-10 22:57 出处:网络
I would like to use boost::shared_ptr<> to encapsulate the lifetime management of a handle. My handle and it\'s creation/destruction functions are declared like this:

I would like to use boost::shared_ptr<> to encapsulate the lifetime management of a handle. My handle and it's creation/destruction functions are declared like this:

typedef const struct MYHANDLE__ FAR* MYHANDLE;

void CloseMyHandle( MYHANDLE );
MYHANDLE CreateMyHandle();

Ideally, I would like to use the boost::shared_ptr<> like this to manage the handle:

boost::shared_ptr< void > my_handle( CreateMyHandle(), &CloseMyHandle );

Unfortunately, because the handle is declared as a const struct * instead of the usual void *, I get errors like this:

boost/smart_ptr/shared_ptr.hpp(199) : error C2440: 'initializing' : cannot convert from 'const MYHANDLE__ *' to 'void *'

I can use a functor to cast the void * to a MYHANDLE like this:

struct DeallocateMyHandle
{ 
    void ope开发者_如何学Crator()( void* handle )
    {
        CloseMyHandle( ( MYHANDLE )handle ); 
    };
};

boost::shared_ptr< void > my_handle( ( void* )CreateMyHandle(), DeallocateMyHandle() );

But, I'd rather have a method that doesn't involve the separate functor. Is there a way to do this just within the boost::shared_ptr<> constructor that I'm not seeing? Or, am I stuck with the functor?

Thanks, PaulH


Why not use:

boost::shared_ptr< const MYHANDLE__ > my_handle( CreateMyHandle(), &CloseMyHandle );

PS. Note the use of double underscore is not allowed (it is reserved for the implementation).
See: Rules about identifers


If HANDLE is a public type, but the type it points to is not, there's a really easy way to write this:

template <typename T> struct unpointer { };
template <typename T> struct unpointer<T*> { typedef T type; };
boost::shared_ptr<typename unpointer<MYHANDLE>::type> my_handle(
  CreateMyHandle(), &CloseMyHandle);

(If you're using a really old version of VC++ or gcc you probably have to omit the "typename" there.)

Of course this gets a bit verbose and tedious. If you're only got one handle type to deal with, you probably to write this:

typedef typename unpointer<MYHANDLE>::type MYHANDLEREF;
typedef boost::shared_ptr<MYHANDLEREF> my_shared_ptr;

If you've got all kinds of handles to wrap (and since it looks like you're doing Win32 API stuff, you probably do), create a template that wraps things up at whatever level you prefer (a class template that just generates the types, a handle_ptr<T> that subclasses shared_ptr<unpointer<T>> and adds the default deleted for you, a handle_ref<T> that uses a shared_ptr behind the scenes to fake being a MYHANDLE & instead of faking being what MYHANDLE is a pointer to, etc.)


Your shared_ptr type needs to be this:

boost::shared_ptr< const MYHANDLE__ FAR>

That way when shared_ptr makes a pointer out of it, it becomes:

const MYHANDLE__ FAR*

Which matches your MYHANDLE type exactly:

#include <boost/shared_ptr.hpp>

struct MYHANDLE__ {};
typedef const MYHANDLE__* MYHANDLE;

void CloseMyHandle(MYHANDLE) {}
MYHANDLE CreateMyHandle(void) { return 0; }

int main()
{
    typedef boost::shared_ptr<const MYHANDLE__> ptr_type;
    ptr_type my_handle( CreateMyHandle(), &CloseMyHandle );
}

Note, I really doubt you need FAR, that's from the 16-bit ages. It expands to either far or nothing, depending on if you're compiling for 16-bit (hint: you aren't compiling to 16-bit. :) ). far isn't even an extension anymore, as far as I know.

Also, like Martin said don't use double-underscores anywhere.

0

精彩评论

暂无评论...
验证码 换一张
取 消