我应该在堆上创建一个新的 QDomDocument 吗?
Should I create a new QDomDocument on the heap?
我将加载多个 XML 文件,每个文件都放入一个 QDomDocument
,然后使用 QMap
将一个标识字符串与每个文档相关联。我应该在地图中存储 QDomDocument
还是指向 QDomDocument
的指针?即,以下哪个示例更符合 Qt 最佳设计实践。
我怀疑示例 A 是首选。我看到的所有代码示例都只是在堆栈上创建一个本地 QDomDocument
。并且,sizeof( QDomDocument )
是 4 个字节;所以,QDomDocument
可能是一个薄包装器,可以在不影响性能的情况下进行浅层复制。
A:地图包含 QDomDocument
个实例
class 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
个实例的指针
class 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
}
};
很明显,您的 QDomDocument 在范围结束时被删除:
{ // scope starts here
// create document on the stack
QDomDocument doc;
...
docs["alpha"] = doc;
} // scope ends here, stack is cleaned, doc is deleted
在堆上创建 QDomDocument 可以解决问题,但可能不是最佳解决方案。例如,这也应该可以正常工作:
{
...
docs["alpha"] = QDomDocument();
docs["alpha"].setContent( &file );
...
}
OP 的怀疑是完全正确的:QDomDocument
通过其基数 class、QDomNode
.
持有指向其实现 (PIMPL) 的指针
虽然 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,我们看到 QDomDocument
的一个空析构函数,它的基础 class 析构函数揭示了一个引用计数机制:
QDomNode::~QDomNode()
{
if (impl && !impl->ref.deref())
delete impl;
}
复制构造中计数增加:
QDomNode::QDomNode(const QDomNode &n)
{
impl = n.impl;
if (impl)
impl->ref.ref();
}
还有作业:
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;
}
因此方法 A 是合法且安全的,并且不存在内存处理问题。
我还要指出,使用 QMap::insert
而不是下标运算符的性能更高一些。
正在做:
QDomDocument doc;
doc.setContent( &file );
docs["alpha"] = doc;
或
docs["alpha"] = QDomDocument();
docs["alpha"].setContent( &file );
都会产生这个:
- 创建了一个
QDomDocument
对象(临时的,在第二个片段中)
- 创建另一个
QDomDocument
对象(在地图内)调用 docs["alpha"]
- 后者分配给第一个。
使用
docs.insert("alpha", QDomDocument());
docs["alpha"].setContent( &file );
只会调用临时构造函数和地图项复制构造函数。
我将加载多个 XML 文件,每个文件都放入一个 QDomDocument
,然后使用 QMap
将一个标识字符串与每个文档相关联。我应该在地图中存储 QDomDocument
还是指向 QDomDocument
的指针?即,以下哪个示例更符合 Qt 最佳设计实践。
我怀疑示例 A 是首选。我看到的所有代码示例都只是在堆栈上创建一个本地 QDomDocument
。并且,sizeof( QDomDocument )
是 4 个字节;所以,QDomDocument
可能是一个薄包装器,可以在不影响性能的情况下进行浅层复制。
A:地图包含 QDomDocument
个实例
class 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
个实例的指针
class 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
}
};
很明显,您的 QDomDocument 在范围结束时被删除:
{ // scope starts here
// create document on the stack
QDomDocument doc;
...
docs["alpha"] = doc;
} // scope ends here, stack is cleaned, doc is deleted
在堆上创建 QDomDocument 可以解决问题,但可能不是最佳解决方案。例如,这也应该可以正常工作:
{
...
docs["alpha"] = QDomDocument();
docs["alpha"].setContent( &file );
...
}
OP 的怀疑是完全正确的:QDomDocument
通过其基数 class、QDomNode
.
虽然 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,我们看到 QDomDocument
的一个空析构函数,它的基础 class 析构函数揭示了一个引用计数机制:
QDomNode::~QDomNode()
{
if (impl && !impl->ref.deref())
delete impl;
}
复制构造中计数增加:
QDomNode::QDomNode(const QDomNode &n)
{
impl = n.impl;
if (impl)
impl->ref.ref();
}
还有作业:
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;
}
因此方法 A 是合法且安全的,并且不存在内存处理问题。
我还要指出,使用 QMap::insert
而不是下标运算符的性能更高一些。
正在做:
QDomDocument doc;
doc.setContent( &file );
docs["alpha"] = doc;
或
docs["alpha"] = QDomDocument();
docs["alpha"].setContent( &file );
都会产生这个:
- 创建了一个
QDomDocument
对象(临时的,在第二个片段中) - 创建另一个
QDomDocument
对象(在地图内)调用docs["alpha"]
- 后者分配给第一个。
使用
docs.insert("alpha", QDomDocument());
docs["alpha"].setContent( &file );
只会调用临时构造函数和地图项复制构造函数。