views:

67

answers:

1

I have a for loop that iterates through an XML document and finds a specified attribute, the pointer that points to the current node sits inside a boost::interprocess::unique_ptr and has a custom deletor to call the object's release() function. It seems that on every loop iteration the pointer gets deleted, but the release() function throws when that happens.

Could anyone suggest a solution? I thought about implementing a mechanism to check if it should be deleted, but I'm not sure how I'd do that...

Code:

typedef bi::unique_ptr<DOMNodeIterator, release_deleter> iterator_ptr;
typedef bi::unique_ptr<DOMNode, release_deleter> node_ptr;

iterator_ptr itera(document->createNodeIterator(rootelement, DOMNodeFilter::SHOW_ALL, NULL, true));

for(node_ptr current(itera->nextNode()); current != 0; current.reset(itera->nextNode())) // throws after one iteration...
{   

....

objects release()

void DOMElementNSImpl::release()
{
    if (fNode.isOwned() && !fNode.isToBeReleased())
        throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager);  // throws here if released after each loop iteration

    DOMDocumentImpl* doc = (DOMDocumentImpl*) fParent.fOwnerDocument;
    if (doc) {
        fNode.callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0);
        fParent.release();
        doc->release(this, DOMMemoryManager::ELEMENT_NS_OBJECT);
    }
    else {
        // shouldn't reach here
        throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager);
    }
}

deleter:

struct release_deleter
{
    template <typename T>
    void operator()(T* pPtr) const
    {
        pPtr->release();
    }
};

EDIT:

virtual DOMNodeIterator *createNodeIterator(DOMNode* root,
                                            DOMNodeFilter::ShowType whatToShow,
                                            DOMNodeFilter* filter,
                                            bool entityReferenceExpansion) = 0;


virtual DOMNode*           nextNode() = 0;
+2  A: 

I don't have visual 2010 for compiling and debugging at work, on ly at home. so I cannot be sure.

But Frankly I really do not like the concept that your iterator owns your pointer.

Your collection owns the pointer, the iterator doesn't ! its not its role..

In C++0x there are an complement to shared_ptr that is std::weak_ptr that you can construct from shared_ptr , allowing to consult and change the data, but having nothing to do with ownership, except becoming more or less inaccessible when the pointer onwed by the shared_ptr is released.

I would use a sort of std::weak_ptr for your iterators. But for unique_ptr I would guess it is a simple pointer over your data that takes the role of weak reference.

EDIT:

DOMNodeIterator * pIter = document->createNodeIterator(rootelement, DOMNodeFilter::SHOW_ALL, NULL, true);

if(pIter==NULL)
{
    return;
}

while(true) // be careful to infinite loops
{
    DOMNode * pNode = pIter->nextNode();
    if (pNode==NULL)
    {
        break;  
    }

    // ... your visiting the nodes here.
}
Stephane Rolland
so if I understand correctly, current should be a weak_ptr and the iterator can still be a unique_ptr?
Tony
compiled with VS2003, using boost, not C++0x
Tony
sorry weak_ptr are shared_ptr counterpart, not unique_ptr counter_part (I have edited my post). I would use a simple pointer.
Stephane Rolland
can you show me an example with the code i provided?
Tony
could you give me the prototype and implementation of `document->createNodeIterator` and `itera->nextNode`. I need to know precisely.
Stephane Rolland
edit your post and put them at the end
Stephane Rolland
@Stephane, I have put the signatures already... I will see if I can find implementation...
Tony
Do you use MSXML as an XML parser ?
Stephane Rolland
I'm using xerces-C++ and those functions I posted are part of that library. You can find it here: http://xerces.apache.org/xerces-c/
Tony
hmm... let me think about it a moment. I may have been wrong in my answer :-)
Stephane Rolland
@Tony, I made a proposal in my answer, could you tell me if it works or not ? I have neither boost nor xerces to compile and to test...
Stephane Rolland
the last line upNode = upIter->nextNode(); does not compile because of incompatible types, nextNode() returns a raw pointer and upNode is a unique_ptr, so it tried with reset() but it does not like it. Same exception. I think deleting the node while in the loop might be the issue... What do you think?
Tony
hey hey :-) I give another try, tell me if my new proposal works :-)
Stephane Rolland
hey, thx for the effort, it looked promising, but when upNode goes out of scope we have the same problem. :(
Tony
Well I looked briefly at this IBM page about xerces, and at **none** of the call of createNodeIterator corresponds to any call to release() http://www.ibm.com/developerworks/xml/library/x-xercc2/sidefile2.html Surely the NodeIterator is part of the underlying collection, and the collection manage the scope of the NodeIterator.
Stephane Rolland
so this conversation was pointless, cause I don't need to use smart_ptrs and just stick with raw pointers?
Tony
Well, it is part of IBM guide to xerces... It should be truthful.
Stephane Rolland
So yes, the conversion was pointless :-)
Stephane Rolland