我应该在堆上创建一个新的QDomDocument吗?

问题描述 投票:1回答:2

我将多个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
  }
};

B。映射包含指向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
  }
};
c++ qt memory-management qdomdocument
2个回答
3
投票

OP的怀疑是正确的:QDomDocument通过其基类QDomNode持有一个指向其实现(PIMPL)的指针。

虽然fonZ正确地说原始对象将超出范围并被破坏,但是存储在映射中的副本将使(共享)实现保持活动状态。看一下the source,我们看到了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 );

将仅调用临时构造函数和地图项copy-constructor。


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 );
    ...    
} 
© www.soinside.com 2019 - 2024. All rights reserved.