Is there a way to specialize how a smart_ptr<T> releases the T?

I am trying to wrapper around a C library (specifically, libxml2) so that I can use it within a C++ program. (yes, I am aware of libxml++ - but it doesn't play nice with libxslt). If the core libxml2 objects were internally reference counted, I could use an intrusive_ptr, and have the friend intrusive_ptr_release call libxml2's release function, and all would be well - but unfortunately libxml2 does not internally reference count the objects (at least, not in a way I have seen). If there were a way to specialize smart_ptr<T> such that instead of the destructor calling delete(), it called what I wanted, I'd be set, but I see no way to easily specialize smart_ptr<xmlDoc> in that way - or am I missing something?

2012/10/24 David Hagood <david.hagood@gmail.com>
I am trying to wrapper around a C library (specifically, libxml2) so that I can use it within a C++ program. (yes, I am aware of libxml++ - but it doesn't play nice with libxslt).
If the core libxml2 objects were internally reference counted, I could use an intrusive_ptr, and have the friend intrusive_ptr_release call libxml2's release function, and all would be well - but unfortunately libxml2 does not internally reference count the objects (at least, not in a way I have seen).
If there were a way to specialize smart_ptr<T> such that instead of the destructor calling delete(), it called what I wanted, I'd be set, but I see no way to easily specialize smart_ptr<xmlDoc> in that way - or am I missing something?
Just provide it with your custom Deleter in the ctor. template<class Y, class D> shared_ptr(Y * p, D d);

On 10/23/2012 09:16 PM, TONGARI wrote:
Just provide it with your custom Deleter in the ctor.
template<class Y, class D> shared_ptr(Y * p, D d); OK, thanks.
However - this does require every construction of a shared pointer to be passed that destructor - that seems error prone if it is known that all T must be released by a given call. If shared_ptr defined a release function: template <typename T> class shared_ptr { ... void Release(T *t) { delete(t);} } and used Release where it currently deletes the object, then in a case like mine, all you'd have do to is specialize it: template <> shared_ptr<xmlDoc>::Release(xmlDoc *t) { xmlFreeDoc(t);} and then all shared_ptr<xmlDoc> would correctly release the object. I guess what I can do to avoid the risk would be to derive from shared_ptr and provide the destructor in my ctor.

On 24/10/12 13:21, David Hagood wrote:
On 10/23/2012 09:16 PM, TONGARI wrote:
Just provide it with your custom Deleter in the ctor.
template<class Y, class D> shared_ptr(Y * p, D d); OK, thanks.
However - this does require every construction of a shared pointer to be passed that destructor - that seems error prone if it is known that all T must be released by a given call.
1) your library will be the one creating the shared_ptr, so this wouldn't affect users 2) If the deleter is not passed to the constructor, it will be default-constructed, which is enough for your needs.

On 24/10/12 14:14, Mathias Gaunard wrote:
2) If the deleter is not passed to the constructor, it will be default-constructed, which is enough for your needs.
My bad, that's incorrect. There is no deleter parameter that is part of the type. Must have been with another smart pointer.

On 2012-10-24 13:21, David Hagood wrote:
I guess what I can do to avoid the risk would be to derive from shared_ptr and provide the destructor in my ctor.
Maybe you might be interested in using an intrusive_ptr<> instead, then? Regards, Rutger

On Wed, Oct 24, 2012 at 8:42 AM, Rutger ter Borg <rutger@terborg.net> wrote:
On 2012-10-24 13:21, David Hagood wrote:
I guess what I can do to avoid the risk would be to derive from shared_ptr and provide the destructor in my ctor.
Maybe you might be interested in using an intrusive_ptr<> instead, then?
That, or what about defining operators new and delete for those types? -- François Duranleau

On Wed, Oct 24, 2012 at 8:42 AM, Rutger ter Borg <rutger@terborg.net>
That, or what about defining operators new and delete for those types?
The problem is that operator delete only gets a void *, so there's the risk of it being called incorrectly. Moreover, operator delete has to be a member of the type, and I don't control the type, it comes from libXML2, as I said in my first post.

On 2012-10-24 13:21, David Hagood wrote:
I guess what I can do to avoid the risk would be to derive from shared_ptr and provide the destructor in my ctor.
Maybe you might be interested in using an intrusive_ptr<> instead, then?
Regards,
Rutger As I said in my post: I don't control the object type that is being managed - that is fixed by libXML2. I am only trying to keep the object from being destroyed at the wrong time. Since there is no internal reference count I cannot use an intrusive_ptr, as I said in my first post.

on Wed Oct 24 2012, David Hagood <david.hagood-AT-gmail.com> wrote:
If shared_ptr defined a release function:
template <typename T> class shared_ptr { ... void Release(T *t) { delete(t);} } and used Release where it currently deletes the object, then in a case like mine, all you'd have do to is specialize it:
template <> shared_ptr<xmlDoc>::Release(xmlDoc *t) { xmlFreeDoc(t);}
and then all shared_ptr<xmlDoc> would correctly release the object.
That actually wouldn't work. Consider that there's implicit upcasting all the way to shared_ptr<void>
I guess what I can do to avoid the risk would be to derive from shared_ptr and provide the destructor in my ctor.
The best way to do this is to wrap shared_ptr<xmlDoc> construction in a function that creates the necessary deleter. Then, if you own xmlDoc, you can even make its destructor private, which can prevent people from dynamically allocating them any other way. HTH, -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

Le 24/10/12 13:21, David Hagood a écrit :
On 10/23/2012 09:16 PM, TONGARI wrote:
Just provide it with your custom Deleter in the ctor.
template<class Y, class D> shared_ptr(Y * p, D d); OK, thanks.
However - this does require every construction of a shared pointer to be passed that destructor - that seems error prone if it is known that all T must be released by a given call.
If shared_ptr defined a release function:
template <typename T> class shared_ptr { ... void Release(T *t) { delete(t);} } and used Release where it currently deletes the object, then in a case like mine, all you'd have do to is specialize it:
template <> shared_ptr<xmlDoc>::Release(xmlDoc *t) { xmlFreeDoc(t);}
and then all shared_ptr<xmlDoc> would correctly release the object.
I guess what I can do to avoid the risk would be to derive from shared_ptr and provide the destructor in my ctor.
I see two options: * either you warp a shared_ptr<xmlDoc,YourSpecificDeleter> and force the constructor (the wrapper will have a lot of boiler plate code bat is easy to do) * you create a factory make_shared_xmlDoc that creates a shared_ptr<xmlDoc,YourSpecificDeleter>. While this is not a complete solution is easy to do and should solve most of the issues you are facing. Best, Vicente
participants (8)
-
David Abrahams
-
David Hagood
-
david.hagood@gmail.com
-
Francois Duranleau
-
Mathias Gaunard
-
Rutger ter Borg
-
TONGARI
-
Vicente J. Botet Escriba