Boost logo

Boost :

From: Stefan Seefeld (seefeld_at_[hidden])
Date: 2003-06-25 14:45:44


Hamish Mackenzie wrote:

> Why should the node-wrappers keep the document alive?

for consistency, and convenience. In the same way you can get down from
the document to the individual nodes you can get up: node.parent() and
node.document() provide the means to walk up towards the document root.

node.begin_children() lets you iterate over all current child nodes,
i.e. the nodes it returns will all be valid, thus this iterator
interface is as stable as that of linked lists.
I expect the same from node.parent() and node.document(), i.e. as long
as there is an API to walk the tree, it should return valid objects.

That is not to say that these objects will remain valid over time.
As you point out, erasing the content of a container will invalidate
iterators you may still hold for that container.

Imagine a factory object that is initialized with a dom::node_ptr
(holding configurational data, say). Whenever you access its method,
the object looks up data in the node...

class factory
{
public:
   factory(dom::node_ptr n) : my_node(n) {}
   foo create_foo(); /* access my_node */
   bar create_bar(); /* access my_node */
private:
   dom::node_ptr my_node;
};

factory 'owns' the node, so whereever you instantiate the factory,
you'd read in a dom::document, look up the relevant node, and pass
that to the constructor:

factory *f;
{
   dom::document_ptr document("config.xml");
   dom::node_set set = document.root_node().find("//factory.info");
   f = new factory(set[0]);
} // document and set are now deleted, but factory still references
   // the document through its 'my_node' member

If the document wasn't ref-counted, you'd need to pass it along with
the node to the factory, as only the factory would know when to drop
it (in its destructor, presumably).

> Here is the analogy I think works best...
>
> container --> document
> container::value_type --> node
> container::iterator --> node_iterator
> container::pointer_type --> node_pointer
> container::reference_type --> node_reference

hmm, that makes it look simpler than it actually is: is there really
a single 'value_type' ? Is there really a single iterator ? (iterating
over all child nodes of a given parent and iterating over all attributes
is not the same)
Also, what is a node_reference (as opposed to a pointer) ?

> Consider the following....
>
> std::vector< foo > x;
> ...
> foo * y = &x[0];
> x.erase( x.begin(), x.end() );
>
> I don't expect y to add_ref x. I wouldn't mind if it did, but it
> wouldn't make y any more valid after the call to erase.

agreed. However, you explicitely erase elements, while all I want to
prevent is implicit object destruction just because a reference to it
goes out of scope.

> So the problem with add reffing the document is... what happens if the
> root node or some parent of a node you have a pointer to is erased from
> the document? libxml2 has no way of knowing you have a pointer to a
> child node.

that's right. And adding such a feature may be quite expensive memory /
performance wise. As I said, I don't feel it's a problem, as you would
explicitely remove the node, so you should know what you are doing
anyways. (As you said, you wouldn't even expect an iterator to be valid
after you erase the container's content).

Regards,
                Stefan


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk