crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в [Qt Undo Framework] Борьба с утечками памяти в QUndoCommand'ах
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
Obey-Kun Дата 1.12.2010, 4:47
  Итак. У меня есть команды для создания и для удаления некоторого объекта из модели.

class CreateItemCommand : public QUndoCommand
{
public:
    CreateItemCommand(ItemModel *model, QUndoCommand *parent = 0):
      QUndoCommand(parent),
      m_model(model),
      m_item(new Item) {
    }

    void redo() {
        m_model->addItem(m_item);
    }
    void undo() {
        m_model->removeItem(m_item);
    }
private:
    ItemModel *const m_model;
    Item *const m_item;
};


class RemoveItemCommand : public QUndoCommand
{
public:
    RemoveItemCommand(ItemModel *model, Item *item, QUndoCommand *parent = 0):
      QUndoCommand(parent),
      m_model(model),
      m_item(item) {
    }

    void redo() {
        m_model->removeItem(m_item);
    }
    void undo() {
        m_model->addItem(m_item);
    }
private:
    ItemModel *const m_model;
    Item *const m_item;
};


Всё бы хорошо, но такой простой подход чреват утечками памяти. Если так получилось, что на итем не ссылаются больше никакие команды (то есть они уничтожены тем или иным способом) и он не находится в ItemModel, то он занимает лишнюю память.

Qt Undo Framework устроен так, что команды в могут удаляться в одном из следующих случаев:
  • делается QUndoStack::clear();
  • при отменённой команде в QUndoStack добавляется некоторая другая команда;
  • в QUndoStack установлен лимит количества команд (undoLimit) и мы вышли за его пределы.

Таким образом, команды могут удаляться находясь как в отменённом, так и в применённом состоянии. И контролировать память при этом несколько затруднительно.

В случае собственной модели решение проблемы простое: нигде не храним указатели на Item напрямую. Везде используем QSharedPointer<Item>CreateItemCommand, в RemoveItemCommand и в ItemModel). Не надо заботиться об удалении — этот итем самоудалится, если на него больше ничего не ссылается. Тут даже деструкторы писать не надо.

Всё усложняется, если мы не контролируем то, как хранятся указатели на итемы в ItemModel. Например, если ItemModel унаследован от QGraphicsScene (а там, как известно, итемы хранятся в виде обычных указателей). Как тут быть?

P.S.: по ходу, в примере из документации Qt как раз-таки допущен косяк, из-за которого будет происходить такая утечка памяти — единожды созданные итемы ни при каких условиях не удаляются. Запощу завтра в их багзиллу. upd: http://bugreports.qt.nokia.com/browse/QTBUG-15756
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 28.3.2024, 16:47