1

我将加载多个 XML 文件,每个文件都放入 aQDomDocument中,然后使用 aQMap将标识字符串与每个文档相关联。我应该在地图中存储 aQDomDocument还是指向 a 的指针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
  }
};

B. Map 包含指向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
  }
};
4

2 回答 2

3

OP 的怀疑是完全正确的:QDomDocument通过其基类QDomNode.

虽然fonZ说原始对象将超出范围并被销毁是正确的,但存储在地图中的副本将使(共享)实现保持活动状态。查看源代码,我们看到一个空的析构函数 for QDomDocument,它的基类析构函数揭示了一个引用计数机制:

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 );

只会调用临时构造函数和地图项复制构造函数。

于 2019-09-25T15:25:32.760 回答
0

很明显,当范围结束时,您的 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 );
    ...    
} 
于 2019-09-25T15:00:20.777 回答