Должен ли я создать новый QDomDocument в куче? - PullRequest
1 голос
/ 25 сентября 2019

Я загружу несколько файлов XML, каждый в QDomDocument, а затем использую QMap, чтобы связать идентификационную строку с каждым документом.Должен ли я хранить QDomDocument или указатель на QDomDocument на карте?то есть, какой из следующих примеров больше соответствует лучшим методам проектирования Qt.

Я подозреваю, что пример А предпочтителен.Все примеры кода, которые я вижу, просто создают локальный 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
  }
};

Ответы [ 2 ]

3 голосов
/ 25 сентября 2019

Подозрения ОП вполне верны: QDomDocument содержит указатель на свою реализацию (PIMPL) через свой базовый класс, QDomNode.

В то время как fonZ прав, говоряисходный объект выйдет из области видимости и будет уничтожен, а копия, сохраненная на карте, сохранит (совместно используемую) реализацию.Взглянув на источник , мы увидим пустой деструктор для 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 );

вызовет только временный конструктор и конструктор копирования элемента карты.

0 голосов
/ 25 сентября 2019

Совершенно очевидно, что ваш 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 );
    ...    
} 
...