crossplatform.ru

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

 
Ответить в данную темуНачать новую тему
> [Qt Undo Framework] Борьба с утечками памяти в QUndoCommand'ах
Obey-Kun
  опции профиля:
сообщение 1.12.2010, 4:47
Сообщение #1


Студент
*

Группа: Участник
Сообщений: 96
Регистрация: 24.3.2010
Пользователь №: 1556

Спасибо сказали: 3 раз(а)




Репутация:   0  


Итак. У меня есть команды для создания и для удаления некоторого объекта из модели.

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

Сообщение отредактировал Obey-Kun - 1.12.2010, 5:55
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 22.9.2019, 13:11