Как мне уничтожить объект QPainter / избавиться от утечки памяти drawText ()? - PullRequest
0 голосов
/ 13 марта 2012

Я пытаюсь урезать утечки памяти большого приложения. Используя valgrind, я также видел много случаев утечек памяти при вызове функции drawText() класса QPainter. Это может быть ошибка Qt в соответствии с некоторыми источниками, которые я прочитал, но я подумал, может быть, я смогу избавиться от него, уничтожив объект QPainter, как сказано в документации -> "Не забудьте уничтожить QPainter объект после рисования. "

  • Как правильно это сделать?

Вот один экземпляр журнала valgrind, в котором drawText() вызывает утечку:

127971 ==00:00:05:31.916 24132== 68,594 (768 direct, 67,826 indirect) bytes in 2 blocks     are definitely lost in loss record 4,979 of 4,982
127972 ==00:00:05:31.916 24132==    at 0x4C2683D: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
127973 ==00:00:05:31.916 24132==    by 0x81861FF: ft_mem_qalloc (in /usr/lib64/libfreetype.so.6.6.2)
127974 ==00:00:05:31.916 24132==    by 0x8186242: ft_mem_alloc (in /usr/lib64/libfreetype.so.6.6.2)
127975 ==00:00:05:31.916 24132==    by 0x81876BE: FT_New_Library (in  /usr/lib64/libfreetype.so.6.6.2)
127976 ==00:00:05:31.916 24132==    by 0x81819C3: FT_Init_FreeType (in /usr/lib64/libfreetype.so.6.6.2)
127977 ==00:00:05:31.916 24132==    by 0x54E4667: ??? (in /usr/lib64/libQtGui.so.4.7.1)
127978 ==00:00:05:31.916 24132==    by 0x54E4A64:  QFontEngineFT::init(QFontEngine::FaceId, bool, QFontEngineFT::GlyphFormat) (in  /usr/lib64/libQtGui.so.4.7.1)
127979 ==00:00:05:31.916 24132==    by 0x54DE0B5: QFontEngineX11FT::QFontEngineX11FT(_FcPattern*, QFontDef const&, int) (in /usr/lib64/libQtGui.so.4.7.1)
127980 ==00:00:05:31.916 24132==    by 0x542EE80: ??? (in /usr/lib64/libQtGui.so.4.7.1)
127981 ==00:00:05:31.916 24132==    by 0x543721A: QFontDatabase::load(QFontPrivate const*, int) (in /usr/lib64/libQtGui.so.4.7.1)
127982 ==00:00:05:31.916 24132==    by 0x5414D46: QFontPrivate::engineForScript(int) const (in /usr/lib64/libQtGui.so.4.7.1)
127983 ==00:00:05:31.916 24132==    by 0x5429FDD: QFontMetricsF::leading() const (in /usr/lib64/libQtGui.so.4.7.1)
127984 ==00:00:05:31.916 24132==    by 0x534ED45: ??? (in /usr/lib64/libQtGui.so.4.7.1)
127985 ==00:00:05:31.916 24132==    by 0x534FCBD: QPainter::drawText(QRect const&, int, QString const&, QRect*) (in /usr/lib64/libQtGui.so.4.7.1)
127986 ==00:00:05:31.916 24132==    by 0x5863AC: gui::base::Printer::printTitle() (in /home/bed/workspace/tasks/MemProfile/MemoryProfiling/build-pc-debug/src/application-ui)
127987 ==00:00:05:31.916 24132==    by 0x585559: gui::base::Printer::run() (in /home/bed/workspace/tasks/MemProfile/MemoryProfiling/build-pc-debug/src/application-ui)
127988 ==00:00:05:31.916 24132==    by 0x5D49A5D: ??? (in /usr/lib64/libQtCore.so.4.7.1)
127989 ==00:00:05:31.916 24132==    by 0x7620A3E: start_thread (in /lib64/libpthread- 2.11.3.so)
127990 ==00:00:05:31.916 24132==    by 0x738067C: clone (in /lib64/libc-2.11.3.so)

1 Ответ

1 голос
/ 13 марта 2012

Если вы создаете объект QPainter в стеке (то есть, не используя new), как указано в документации:

void SimpleExampleWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setPen(Qt::blue);
    painter.setFont(QFont("Arial", 30));
    painter.drawText(rect(), Qt::AlignCenter, "Qt");
}

Тогда объект QPainter будет уничтожен, когда он выйдет из области видимости (в примере выше: в конце функции). Причина, по которой в документации упоминается, что вы должны быть осторожны при удалении объекта QPainter, заключается в том, что Qt не будет делать это само по себе, что немного отличается от многих методов управления виджетами Qt.

Итак, скажем, вы динамически распределили этот объект:

void SimpleExampleWidget::paintEvent(QPaintEvent *)
{
    QPainter* painter = new QPainter(this);
    painter->setPen(Qt::blue);
    painter->setFont(QFont("Arial", 30));
    painter->drawText(rect(), Qt::AlignCenter, "Qt");
    // Delete object, since Qt wont do it for you:
    delete painter;
}

Qt сообщает вам, что вы отвечаете за очистку объекта QPainter, что в нашем примере выполняется командой delete. Однако, если вы используете этот подход, вы можете подумать о том, чтобы поместить его в умный указатель, т.е. boost::scoped_ptr<QPainter> painter = new QPainter(this);

void SimpleExampleWidget::paintEvent(QPaintEvent *)
{
    boost::scoped_ptr<QPainter> painter = new QPainter(this);
    painter->setPen(Qt::blue);
    painter->setFont(QFont("Arial", 30));
    painter->drawText(rect(), Qt::AlignCenter, "Qt");
}

Теперь, что касается правильного способа сделать это. Это зависит от того, как часто вам придется создавать объекты QPainter, если вы создаете их локально, как в примере? Если это приводит к дополнительным расходам, подумайте о создании QPainter в качестве переменной-члена и его повторном использовании. (Хотя, если вы беспокоитесь о скорости: «оптимизация на ранних этапах никогда не бывает хорошей идеей» - это то, что следует посвятить сердцу).

Если вы выделяете память динамически с помощью new, помните, что вы также отвечаете за ее удаление. Если вы просто создадите его в стеке, как в самом верхнем примере, вам не нужно беспокоиться, так как он будет уничтожен всякий раз, когда выходит из области, в которой он был создан.

...