4

I have the following class definition and it needs a copy constructor so deep copies are made to copy the raw pointers. Can anybody advice on how to best do this?

Using xerces-c++ for XML

class XMLDocument 
 {
 private:
  typedef std::vector<XML::XMLNode> v_nodes;
 public:
  XMLDocument::XMLDocument();
  XMLDocument::XMLDocument(const XMLDocument& copy); 
  XMLDocument::~XMLDocument();

  XMLDocument& operator=(XMLDocument const& rhs);

  void CreateDocument(const std::string& docname);
  void AddChildNode(XMLNode& node);
  void RemoveNode(XMLNode& node);
  void AddNodeValue(XMLNode& node, const std::string& value);
  void AddNodeValue(XMLNode& node, int value);
  void AddNodeValue(XMLNode& node, double value);
  void AddNodeValue(XMLNode& node, float value);
  std::string GetXMLAttributes();
  std::string GetXMLAttribute(const std::string& attrib);
  std::string GetXMLNodeText(XML::XMLNode& node);
  std::string DumpToString();
  XMLNode GetXPathNode(const std::string xpathXpression);
  XMLNode GetNode(const XMLNode &currentnode);

  typedef v_nodes::iterator nodes_iterator;
  nodes_iterator begin()
  {
   nodes_iterator iter;
   iter = xmlnodes.begin();

   return iter;
  }
  nodes_iterator end()
  {
   nodes_iterator iter;
   iter = xmlnodes.end();

   return iter; 
  }


 private:
  v_nodes xmlnodes;

  bool InitializeXML();
  DOMImplementation* impl; //Abstract
  DOMDocument* document; //Abstract
  DOMElement* rootelement; //Abstract

 };

The DOMDocument is created calling a function and so is the DOMElement. So I can't just call new on these pointers.

Not sure if I just literally recreate all these object?

Example:

document = impl->createDocument(0, "mydoc", 0);

Who's gone on a downvote rage and not given a reason???

4
  • 1
    You should probably mention in your question that you're using this and not your own classes: xerces.apache.org/xerces-c/apiDocs-3/… Commented Nov 3, 2010 at 15:23
  • Do the classes in question have a clone() interface of some sort? If not, you may be SOL if you want to copy the object hierarchy (meaning you'd have to do it manually, either by walking the nodes yourself or by serializing and deserializing the document somehow) Commented Nov 3, 2010 at 15:36
  • No clone that I can see, and what does SOL mean? Commented Nov 3, 2010 at 15:37
  • 1
    With the caveat that it has been a few years since I used it... Beware of memory leaks with Xerces and be very careful how you use memory with it. I suspect the missing copy constructors have something to do with the memory leaks. Commented Nov 3, 2010 at 16:29

5 Answers 5

2
+50

This page might certainly help:
http://icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html

Note their is a difference between writing a copy-constructor and an assignment operator but this point is also discussed in the paper.

Sign up to request clarification or add additional context in comments.

2 Comments

That page contains only "half the truth", as the author had to find out himself: icu-project.org/docs/papers/cpp_report/…
@AudioDroid I definitely missed this one. Thank you for the enlightenment.
2

Writing a copy constructor is always about doing "The Right Thing" for each member variable. Without seeing the API docs for your DOMImplementation etc. it is hard to say what "The Right Thing" would be, here. Perhaps there is a copy constructor for them, or a function to make a deep copy. Perhaps you don't need a deep copy, semantically (e.g. for DOMImplementation).

Bottom line, hard to say without seeing the API docs you surely have lying around...

Edit: So you are using Xerces-C. You didn't tell us that before...

Edit 2: Let's see, then...

The Xerces-C API indeed does not provide any "easy" means of copying a document object, from what I can see. AFAICT, you will have to create a completely new document (impl->createDocument()), and then copy over any attributes and child nodes manually.

This being so awkward, I would raise the question "why do I want to copy my XMLDocument object, anyway? Does it even make sense, on a semantic level?". (Personal experience: If things get ugly while working with a well-used API, chances are you're doing something wrong, because there would be an easy way otherwise. XML is not my strong streak, so I'm out of my depth here.)

5 Comments

This classes not have copy-constructor.
@DevSolar: What about passing this XMLDocument object around and returning it from a function by value? Should I then just always return a pointer? Or a smart_ptr?
@Tony: I don't really see what you're trying to do here. A wrapper around the Xerces-C API? Xerces-C handles DOMDocument objects through pointers, and doesn't allow for (easy) copying of DOMDocuments. Unless you have something specific in mind (and the skill to pull it off), you should heed that, and not trying to "force" it into a different behaviour.
@DevSolar, I just wanted to wrap the complexity of doing standard XML things I need throughout my program in a class and only use the bits from xerces that I need.
Then my wrapper can be used throughout the rest of my program and if anyone ever decides to change what XML lib to use, the whole program is not affected.
1

Devsolar is right about copy constructors. Heed his advice.

Furthermore you really shouldn't be copying the DOM structures. Standard procedure when I am working with XML is to write a handler that gets the data from DOM/SAX and builds a native object based off that structure. Once you are done reading all the DOM/SAX elements you should have constructed in memory either:

  1. A data structure that holds all the data you needed from the XML.
  2. An object built from the XML but decoupled from XML. You use this object within your application. Most likely you will serialize this object to xml in the future.

This way you don't need to copy DOM. You instead build native objects to represent the data. Remember you want to decouple your application from XML. What if in the future you decide to use binary serialization?

1 Comment

Sorry, deleted the copy-constructor comment... it's not always The Right Thing, and I thought it wouldn't be a good general advice.
1

If the deep copying that you want is possible with the library you're using, then the way to go about it is to ensure that every owned data member of your class XMLDocument knows how to copy itself (using its own copy constructor). And so on recursively for each data member's type. In practice this means defining copyable wrapper types from the ground up.

Take care to define exactly what's owned (to be copied) and what's not (existing elsewhere and just referenced).

The main reason for this hierarchical wrapping is that you want C++'s automatic destruction to kick in when some copying of a part fails. But it also greatly simplifies things. And when you get down to the lowest levels of constituent parts, you may get better advice about copying such a smallest part.

Cheers & hth.,

Comments

0

I'd recommend rethinking the ownership rules a little bit. If you want to do a deep copy, chances are you are trying to work around what variable owns the memory of other variables. In your case, it seems like you care about each instance of XMLDocument owning the v_nodes and DOM-related variables.

Another way to resolve the underlying issues is to wrap your instance variables in smart pointers.

In this way, each time you copy construct XMLDocument, you're just bumping the ref count on each of the ivars. Each time the dtor for an XMLDocument instance gets called, the ref count decrements. In essence, you're decoupling the lifetime of each XMLDocument instance from its ivars. Instead, it's the ref count that owns it.

I'm not an expert on xerces, but it's worth checking out various smart ptr implementations, e.g. the boost library.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.