问题
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 ¤tnode);
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???
回答1:
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.
回答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.)
回答3:
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:
- A data structure that holds all the data you needed from the XML.
- 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?
回答4:
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.,
回答5:
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.
来源:https://stackoverflow.com/questions/4088411/implementing-a-copy-constructor