Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Redux: RAII adapter for Xerces

5.00/5 (1 vote)
5 Aug 2010BSD2 min read 8.5K  
A shared_ptr memory manager for the Xerces XML parser

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.

C++
template
class shared_xerces_ptr
{
    // The actual data we're holding
    boost::shared_ptr item_;

    // Function to release Xerces data type with a release member function
    template
    static void do_release(T* item)
    {
        // Only release this if it has no owner
        if (0 == item->getOwnerDocument())
            item->release();
    }
    // Specializations for character types, released by XMLString::release
    template
    static void do_release(char* item)
    {
        XMLString::release(&item);
    }
    template
    static void do_release(XMLCh* item)
    {
        XMLString::release(&item);
    }
public:
...
    // Assignment constructor
    shared_xerces_ptr(T* item)
      : item_(item, do_release )
    {}
    // Release currently held data, if any, to hold another
    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.

C++
template
class shared_xerces_ptr
{
    // The actual data we're holding
    boost::shared_ptr item_;

    // Function to release Xerces data type with a release member function
    template
    static void do_release(T* item)
    {
        // Only release this if it has no owner
        if (0 == item->getOwnerDocument())
            item->release();
    }
    // Specializations for character types, released by XMLString::release
    template
    static void do_release(char* item)
    {
        XMLString::release(&item);
    }
    template
    static void do_release(XMLCh* item)
    {
        XMLString::release(&item);
    }
public:
    // Default constructor
    shared_xerces_ptr()
    {}
    // Assignment constructor
    shared_xerces_ptr(T* item)
      : item_(item, do_release )
    {}
    // Assignment of data to guard
    shared_xerces_ptr& operator=(T* item)
    {
        assign(item);
        return *this;
    }
    // Give up hold on data
    void reset()
    {
        item_.reset();
    }
    // Release currently held data, if any, to hold another
    void assign(T* item)
    {
        item_.reset(item, do_release );
    }
    // Get pointer to the currently held data, if any
    T* get()
    {
        return item_.get();
    }
    const T* get() const
    {
        return item_.get();
    }
    // Return true if no data is held
    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

License

This article, along with any associated source code and files, is licensed under The BSD License