I will load multiple XML files, each into a QDomDocument
, and then use a QMap
to associate an identifying string with each document. Should I store a QDomDocument
or a pointer to a QDomDocument
in the map? i.e., which of the following examples is more in keeping with Qt best design practices.
I suspect that example A is preferred. All the code samples I see just create a local QDomDocument
on the stack. And, sizeof( QDomDocument )
is 4 bytes; so, QDomDocument
is probably a thin wrapper that can be shallow copied without much of a performance hit.
QDomDocument
instancesclass Core
{
private:
QMap<QString, QDomDocument> docs;
public:
Core( void )
{
QFile file( "alpha.xml" );
file.open( QIODevice::ReadOnly );
QDomDocument doc;
doc.setContent( &file );
docs["alpha"] = doc;
// ... etc for other XML files
}
QString findThing( QString const & docName, QString const & thingName )
{
QDomDocument doc = docs[docName];
// ... search the doc for the thing with the given name
}
};
QDomDocument
instancesclass Core
{
private:
QMap<QString, QDomDocument *> docs;
public:
Core( void )
{
QFile file( "alpha.xml" );
file.open( QIODevice::ReadOnly );
QDomDocument * pDoc = new QDomDocument();
pDoc->setContent( &file );
docs["alpha"] = pDoc;
// ... etc for other XML files
}
QString findThing( QString const & docName, QString const & thingName )
{
QDomDocument * pDoc = docs[docName];
// ... search the doc for the thing with the given name
}
};
The OP suspicions are quite right: QDomDocument
holds a pointer to its implementation (PIMPL) through its base class, QDomNode
.
While fonZ is right in saying the original object will go out of scope and destroyed, the copy stored in the map will keep the (shared) implementation alive. Taking a look at the source, we see an empty destructor for QDomDocument
, and its base class destructor reveals a reference counting mechanism:
QDomNode::~QDomNode()
{
if (impl && !impl->ref.deref())
delete impl;
}
the count gets incremented in copy construction:
QDomNode::QDomNode(const QDomNode &n)
{
impl = n.impl;
if (impl)
impl->ref.ref();
}
and in assignment as well:
QDomNode& QDomNode::operator=(const QDomNode &n)
{
if (n.impl)
n.impl->ref.ref();
if (impl && !impl->ref.deref())
delete impl;
impl = n.impl;
return *this;
}
thus method A is legal and safe, and bears no memory handling concerns.
I would also point out that using QMap::insert
instead of the subscript operator is a bit more performant.
Doing:
QDomDocument doc;
doc.setContent( &file );
docs["alpha"] = doc;
or
docs["alpha"] = QDomDocument();
docs["alpha"].setContent( &file );
will both produce this:
QDomDocument
object is created (a temporary, in the second snippet)QDomDocument
object is created (inside the map) calling docs["alpha"]
Using
docs.insert("alpha", QDomDocument());
docs["alpha"].setContent( &file );
will only call the temporary constructor and the map item copy-constructor.