In my previous entry, C++ RAII adapter for Xerces, I presented a simple memory management wrapper for Xerces types. Because of the way Xerces manages memory, I said, the quite handy boost::shared_ptr
couldn't be used, so I wrote the memory management code myself to produce a safe wrapper in the style of std::auto_ptr
.
However, as Alf P. Steinbach pointed out, I was wrong, in that boost::shared_ptr
could be used by taking advantage of the custom deleter facility offered by that class. One benefit is that I can get rid of my hand-rolled memory management, but on the other hand, I’ll have to adjust the public
interface to reflect different semantics.
The custom deleter version of the boost::shared_ptr
takes a deleter function as a constructor argument, and is perfectly happy with taking a static
member function.
template
class shared_xerces_ptr
{
boost::shared_ptr item_;
template
static void do_release(T* item)
{
if (0 == item->getOwnerDocument())
item->release();
}
template
static void do_release(char* item)
{
XMLString::release(&item);
}
template
static void do_release(XMLCh* item)
{
XMLString::release(&item);
}
public:
...
shared_xerces_ptr(T* item)
: item_(item, do_release )
{}
void assign(T* item)
{
item_.reset(item, xerces_deleter );
}
...
Unlike my previous effort, the auto_xerces_ptr
, there is no need here to write a custom destructor, as the boost::shared_ptr
takes care of that. Neither do I need to hide the copy constructor or assignment operator, as the boost::shared_ptr
makes those safe, too.
But by the same token, I can’t provide a xerces_release
function to release the data, like I did in auto_xerces_ptr
. Since the boost::shared_ptr
is safe with multiple copies, I cannot guarantee when held data will be released; if there are multiple references to it, it will only be released when the last reference is gone. For the same reason, the auto_xerces_ptr::yield
would make no sense in the shared_xerces_ptr
class, simply because there might be other instances referencing the data. Instead, I’ll provide a reset
function, and leave it at that.
The final difference is to make the assignment operator work like we're used to, and make it chainable.
template
class shared_xerces_ptr
{
boost::shared_ptr item_;
template
static void do_release(T* item)
{
if (0 == item->getOwnerDocument())
item->release();
}
template
static void do_release(char* item)
{
XMLString::release(&item);
}
template
static void do_release(XMLCh* item)
{
XMLString::release(&item);
}
public:
shared_xerces_ptr()
{}
shared_xerces_ptr(T* item)
: item_(item, do_release )
{}
shared_xerces_ptr& operator=(T* item)
{
assign(item);
return *this;
}
void reset()
{
item_.reset();
}
void assign(T* item)
{
item_.reset(item, do_release );
}
T* get()
{
return item_.get();
}
const T* get() const
{
return item_.get();
}
bool is_released() const
{
return (0 == item_.get());
}
};
There you have it. Not a replacement for auto_xerces_ptr
, but a complement. Again, if you find it useful, or have suggestions for improvements, please let me know.
Tagged:
C++,
template,
Xerces,
XML